1module m_wxml_core
2
3#ifndef DUMMYLIB
4  use fox_m_fsys_abort_flush, only: pxfabort
5  use fox_m_fsys_array_str, only: vs_str, str_vs, vs_str_alloc
6  use fox_m_fsys_string, only: toLower
7  use fox_m_utils_uri, only: URI, parseURI, destroyURI
8  use m_common_attrs, only: dictionary_t, getLength, get_key, get_value, &
9    hasKey, add_item_to_dict, init_dict, reset_dict, destroy_dict, &
10    getWhitespaceHandling, sortAttrs
11  use m_common_buffer, only: buffer_t, len, add_to_buffer, reset_buffer, &
12    dump_buffer
13  use m_common_charset, only: XML1_0, XML1_1, checkChars
14  use m_common_element, only: parse_dtd_element, parse_dtd_attlist
15  use m_common_elstack, only: elstack_t, len, get_top_elstack, pop_elstack, &
16    is_empty, init_elstack, push_elstack, destroy_elstack
17  use m_common_entities, only: existing_entity, is_unparsed_entity
18  use m_common_error, only: FoX_warning_base, FoX_error_base, FoX_fatal_base, &
19    error_stack, in_error, FoX_get_fatal_errors, FoX_get_fatal_warnings
20  use m_common_io, only: get_unit
21  use m_common_namecheck, only: checkEncName, checkName, checkQName, &
22    checkCharacterEntityReference, checkPublicId, prefixOfQName, &
23    localpartofQName, checkPEDef, checkPseudoAttValue, checkAttValue, checkNCName, &
24    likeCharacterEntityReference, checkCharacterEntityReference
25  use m_common_namespaces, only: namespaceDictionary, getnamespaceURI, &
26  initnamespaceDictionary, addDefaultNS, destroyNamespaceDictionary, &
27  addPrefixedNS, isPrefixInForce, checkNamespacesWriting, checkEndNamespaces
28  use m_common_notations, only: add_notation, notation_exists
29  use m_common_struct, only: xml_doc_state, init_xml_doc_state, destroy_xml_doc_state, &
30    register_internal_PE, register_external_PE, register_internal_GE, register_external_GE
31  use m_wxml_escape, only: escape_string
32#ifdef PGF90
33  use m_common_element, only : element_t
34#endif
35#endif
36
37  implicit none
38  private
39
40#ifndef DUMMYLIB
41  integer, parameter :: indent_inc = 2
42  ! TOHW should we let this be set?
43
44  !Output State Machines
45  ! status wrt root element:
46  integer, parameter :: WXML_STATE_1_JUST_OPENED = 0
47  !File is just opened, nothing written to it yet.
48  integer, parameter :: WXML_STATE_1_BEFORE_ROOT = 1
49  !File has been opened, something has been written, but no root element yet.
50  integer, parameter :: WXML_STATE_1_DURING_ROOT = 2
51  !The root element has been opened but not closed
52  integer, parameter :: WXML_STATE_1_AFTER_ROOT = 3
53  !The root element has been opened but not closed
54
55  ! status wrt tags:
56  integer, parameter :: WXML_STATE_2_OUTSIDE_TAG = 0
57  !We are not within a tag.
58  integer, parameter :: WXML_STATE_2_INSIDE_PI = 1
59  !We are inside a Processing Instruction tag
60  integer, parameter :: WXML_STATE_2_INSIDE_ELEMENT = 2
61  !We are inside an element tag.
62  integer, parameter :: WXML_STATE_2_IN_CHARDATA = 3
63  !We are inside deliberately-constructed text. (this is only necessary for preserve_whitespace)
64
65  ! status wrt DTD
66  integer, parameter :: WXML_STATE_3_BEFORE_DTD = 0
67  ! No DTD has been encountered yet.
68  integer, parameter :: WXML_STATE_3_DURING_DTD = 1
69  ! Halfway throught outputting a DTD
70  integer, parameter :: WXML_STATE_3_INSIDE_INTSUBSET = 2
71  !We are inside the internal subset definition
72  integer, parameter :: WXML_STATE_3_AFTER_DTD = 3
73  ! Finished outputting a DTD
74#endif
75
76
77  type xmlf_t
78    private
79#ifdef DUMMYLIB
80    integer :: i = 0
81#else
82    type(xml_doc_state) :: xds
83    integer                   :: lun = -1
84    type(buffer_t)            :: buffer
85    type(elstack_t)           :: stack
86    type(dictionary_t)        :: dict
87    integer                   :: state_1 = -1
88    integer                   :: state_2 = -1
89    integer                   :: state_3 = -1
90    ! Holder for extra information for other writers. See
91    ! table with getter and setter below:
92    integer                   :: extended_data = 0
93    logical                   :: minimize_overrun = .true.
94    logical                   :: pretty_print = .false.
95    logical                   :: canonical = .false.
96    integer                   :: indent = 0
97    character, pointer        :: name(:)
98    logical                   :: namespace = .true.
99    type(namespaceDictionary) :: nsDict
100#endif
101  end type xmlf_t
102
103  public :: xmlf_t
104
105  public :: xml_OpenFile
106  public :: xml_NewElement
107  public :: xml_EndElement
108  public :: xml_Close
109  public :: xml_AddXMLDeclaration
110  public :: xml_AddXMLStylesheet
111  public :: xml_AddXMLPI
112  public :: xml_AddComment
113  public :: xml_AddCharacters
114  public :: xml_AddNewline
115  public :: xml_AddEntityReference
116  public :: xml_AddAttribute
117  public :: xml_AddPseudoAttribute
118  public :: xml_DeclareNamespace
119  public :: xml_UnDeclareNamespace
120  public :: xml_AddDOCTYPE
121  public :: xml_AddParameterEntity
122  public :: xml_AddInternalEntity
123  public :: xml_AddExternalEntity
124  public :: xml_AddNotation
125  public :: xml_AddElementToDTD
126  public :: xml_AddAttlistToDTD
127  public :: xml_AddPEreferenceToDTD
128
129  public :: xmlf_Name
130  public :: xmlf_OpenTag
131
132  public :: xmlf_SetPretty_print
133  public :: xmlf_GetPretty_print
134  public :: xmlf_SetExtendedData
135  public :: xmlf_GetExtendedData
136
137  interface xml_AddCharacters
138    module procedure xml_AddCharacters_Ch
139  end interface
140  interface xml_AddAttribute
141    module procedure xml_AddAttribute_Ch
142  end interface
143  interface xml_AddPseudoAttribute
144    module procedure xml_AddPseudoAttribute_Ch
145  end interface
146
147#ifndef DUMMYLIB
148  !overload error handlers to allow file info
149  interface wxml_warning
150    module procedure wxml_warning_xf, FoX_warning_base
151  end interface
152  interface wxml_error
153    module procedure wxml_error_xf, FoX_error_base
154  end interface
155  interface wxml_fatal
156    module procedure wxml_fatal_xf, FoX_fatal_base
157  end interface
158
159  ! Heuristic (approximate) target for justification of output
160  ! only gets used for outputting attributes
161  integer, parameter  :: COLUMNS = 80
162
163  ! TOHW - This is the longest string that may be output without
164  ! a newline. The buffer must not be larger than this, but its size
165  ! can be tuned for performance.
166  !lowest value found so far is 4096, for NAG. We use 1024 just in case.
167  integer, parameter  :: xml_recl = 1024
168#endif
169
170contains
171
172  subroutine xml_OpenFile(filename, xf, unit, iostat, preserve_whitespace, &
173    pretty_print, minimize_overrun, canonical, replace, addDecl, warning, &
174    validate, namespace)
175    character(len=*), intent(in)  :: filename
176    type(xmlf_t), intent(inout)   :: xf
177    integer, intent(in), optional :: unit
178    integer, intent(out), optional :: iostat
179    logical, intent(in), optional :: preserve_whitespace
180    logical, intent(in), optional :: pretty_print
181    logical, intent(in), optional :: minimize_overrun
182    logical, intent(in), optional :: canonical
183    logical, intent(in), optional :: replace
184    logical, intent(in), optional :: addDecl
185    logical, intent(in), optional :: warning
186    logical, intent(in), optional :: validate
187    logical, intent(in), optional :: namespace
188
189#ifdef DUMMYLIB
190    if (present(iostat)) iostat = 0
191#else
192    logical :: repl, decl
193    integer :: iostat_
194
195    if (xf%lun /= -1) &
196      call wxml_fatal("Trying to reopen an already-open XML file")
197
198    if (present(replace)) then
199      repl = replace
200    else
201      repl = .true.
202    endif
203    if (present(addDecl)) then
204      decl = addDecl
205    else
206      decl = .true.
207    endif
208    if (present(iostat)) iostat = 0
209
210    allocate(xf%name(0))
211
212    if (present(unit)) then
213      if (unit==-1) then
214        call get_unit(xf%lun,iostat_)
215        if (iostat_ /= 0) then
216          if (present(iostat)) iostat = iostat_
217          return
218        endif
219      else
220        xf%lun = unit
221      endif
222    else
223      call get_unit(xf%lun,iostat_)
224      if (iostat_ /= 0) then
225        if (present(iostat)) iostat = iostat_
226        return
227      endif
228    endif
229
230    ! Use large I/O buffer in case the O.S./Compiler combination
231    ! has hard-limits by default (i.e., NAGWare f95's 1024 byte limit)
232    ! This is related to the maximum size of the buffer.
233    ! TOHW - This is the longest string that may be output without
234    ! a newline. The buffer must not be larger than this, but its size
235    ! can be tuned for performance.
236
237    if (repl) then
238      ! NAG insists on unnecessary duplication of iostat etc here
239      if (present(iostat)) then
240        open(unit=xf%lun, file=filename, form="formatted", status="replace", &
241          action="write", recl=xml_recl, iostat=iostat)
242      else
243        open(unit=xf%lun, file=filename, form="formatted", status="replace", &
244          action="write", recl=xml_recl)
245      endif
246    else
247      if (present(iostat)) then
248        open(unit=xf%lun, file=filename, form="formatted", status="new", &
249          action="write", recl=xml_recl, iostat=iostat)
250      else
251        open(unit=xf%lun, file=filename, form="formatted", status="new", &
252          action="write", recl=xml_recl)
253      endif
254    endif
255
256    call init_elstack(xf%stack)
257
258    call init_dict(xf%dict)
259    !NB it can make no difference which XML version we are using
260    !until after we output the XML declaration. So we set it to
261    !1.0 for the moment & reset below.
262    ! Actually, this is done automatically in initializing xf%xds
263    call init_xml_doc_state(xf%xds)
264    xf%xds%documentURI => vs_str_alloc(filename)
265
266    if (present(warning)) then
267      xf%xds%warning = warning
268    else
269      xf%xds%warning = .false.
270    endif
271    if (present(validate)) then
272      xf%xds%valid = validate
273    else
274      xf%xds%valid = .false.
275    endif
276    xf%state_1 = WXML_STATE_1_JUST_OPENED
277    xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
278    xf%state_3 = WXML_STATE_3_BEFORE_DTD
279
280    if (present(pretty_print)) then
281      xf%pretty_print = pretty_print
282    else
283      xf%pretty_print = .true.
284    endif
285    if (present(minimize_overrun)) then
286      xf%minimize_overrun = minimize_overrun
287    else
288      xf%minimize_overrun = .false.
289    endif
290    if (present(preserve_whitespace)) then
291      xf%pretty_print = .not.preserve_whitespace
292      xf%minimize_overrun = preserve_whitespace
293    endif
294    if (present(canonical)) then
295      xf%canonical = canonical
296    else
297      xf%canonical = .false.
298    endif
299! FIXME interplay of above options
300
301    xf%indent = 0
302
303    if (decl) then
304      call xml_AddXMLDeclaration(xf,encoding='UTF-8')
305      ! which will reset the buffer itself
306    else
307      call reset_buffer(xf%buffer, xf%lun, xf%xds%xml_version)
308    endif
309
310    if (present(namespace)) then
311      xf%namespace = namespace
312    else
313      xf%namespace = .true.
314    endif
315    if (xf%namespace) &
316      call initNamespaceDictionary(xf%nsDict)
317#endif
318  end subroutine xml_OpenFile
319
320
321  subroutine xml_AddXMLDeclaration(xf, version, encoding, standalone)
322    type(xmlf_t), intent(inout)   :: xf
323    character(len=*), intent(in), optional :: version
324    character(len=*), intent(in), optional :: encoding
325    logical, intent(in), optional :: standalone
326
327#ifndef DUMMYLIB
328    call check_xf(xf)
329    ! Don't need to call checkChars on args, everything is checked
330    ! fully below anyway.
331
332    if (xf%state_1 /= WXML_STATE_1_JUST_OPENED) &
333      call wxml_error("Tried to put XML declaration in wrong place")
334
335    call reset_buffer(xf%buffer, xf%lun, xf%xds%xml_version)
336
337    call xml_AddXMLPI(xf, "xml", xml=.true.)
338    if (present(version)) then
339      if (version =="1.0") then
340        xf%xds%xml_version = XML1_0
341        call xml_AddPseudoAttribute(xf, "version", version)
342      elseif (version=="1.1") then
343        xf%xds%xml_version = XML1_1
344        call xml_AddPseudoAttribute(xf, "version", version)
345      else
346        call wxml_error("Invalid XML version.")
347      endif
348    else
349      call xml_AddPseudoAttribute(xf, "version", "1.0")
350      xf%xds%xml_version = XML1_0
351    endif
352    if (present(encoding)) then
353      if (.not.checkEncName(encoding)) &
354        call wxml_error("Invalid encoding name: "//encoding)
355      if (encoding /= 'UTF-8' .and. encoding /= 'utf-8') &
356        call wxml_warning(xf, "Non-default encoding specified: "//encoding)
357      call xml_AddPseudoAttribute(xf, "encoding", encoding)
358    endif
359    if (present(standalone)) then
360      xf%xds%standalone_declared = .true.
361      xf%xds%standalone = standalone
362      if (standalone) then
363        call xml_AddPseudoAttribute(xf, "standalone", "yes")
364      else
365        call xml_AddPseudoAttribute(xf, "standalone", "no")
366      endif
367    endif
368    call close_start_tag(xf)
369    ! We have to close explicitly here to ensure nothing gets tied
370    ! up in the XML declaration
371    xf%state_1 = WXML_STATE_1_BEFORE_ROOT
372#endif
373  end subroutine xml_AddXMLDeclaration
374
375
376  subroutine xml_AddDOCTYPE(xf, name, system, public)
377    type(xmlf_t), intent(inout) :: xf
378    character(len=*), intent(in) :: name
379    character(len=*), intent(in), optional :: system, public
380
381#ifndef DUMMYLIB
382    type(URI), pointer :: URIref
383
384    call check_xf(xf)
385
386    if (xf%namespace) then
387      if (.not.checkQName(name, xf%xds%xml_version)) &
388        call wxml_error("Invalid Name in DTD "//name)
389    else
390      if (.not.checkName(name, xf%xds%xml_version)) &
391        call wxml_error("Invalid Name in DTD "//name)
392    endif
393
394    if (present(system)) then
395      URIref => parseURI(system)
396      if (.not.associated(URIref)) call wxml_error("xml_AddDOCTYPE: Invalid SYSTEM URI")
397      call destroyURI(URIref)
398    endif
399    if (present(public)) then
400      if (.not.checkPublicId(public)) call wxml_error("xml_AddDOCTYPE: Invalid PUBLIC ID")
401    endif
402
403    if (present(public).and..not.present(system)) &
404      call wxml_error('xml_AddDOCTYPE: PUBLIC supplied without SYSTEM for: '//name)
405
406    ! By having an external ID we probably render this non-standalone (unless we've said that it is in the declaration)
407    if (present(system).and..not.xf%xds%standalone_declared) &
408      xf%xds%standalone=.false.
409
410    call close_start_tag(xf)
411
412    if (xf%state_1 /= WXML_STATE_1_BEFORE_ROOT) &
413      call wxml_error("Tried to put XML DOCTYPE in wrong place: "//name)
414
415    if (xf%state_3 /= WXML_STATE_3_BEFORE_DTD) then
416      call wxml_error("Tried to output more than one DOCTYPE declaration: "//name)
417    else
418      xf%state_3 = WXML_STATE_3_DURING_DTD
419    endif
420
421    call add_eol(xf)
422    call add_to_buffer("<!DOCTYPE "//name, xf%buffer, .false.)
423
424    deallocate(xf%name)
425    allocate(xf%name(len(name)))
426    xf%name = vs_str(name)
427
428    if (present(system)) then
429      if (present(public)) then
430        call add_to_buffer(" PUBLIC", xf%buffer, .false.)
431        call add_to_buffer(" """//public//"""", xf%buffer, .true.)
432      else
433        call add_to_buffer(" SYSTEM", xf%buffer, .false.)
434      endif
435      if (scan(system, """")/=0) then
436        call add_to_buffer(" '"//system//"'", xf%buffer, .true.)
437      else
438        call add_to_buffer(" """//system//"""", xf%buffer, .true.)
439      endif
440    endif
441#endif
442  end subroutine xml_AddDOCTYPE
443
444
445  subroutine xml_AddParameterEntity(xf, name, PEdef, system, public)
446    type(xmlf_t), intent(inout) :: xf
447    character(len=*), intent(in) :: name
448    character(len=*), intent(in), optional :: PEDef
449    character(len=*), intent(in), optional :: system
450    character(len=*), intent(in), optional :: public
451
452#ifndef DUMMYLIB
453    type(URI), pointer :: URIref
454#ifdef PGF90
455    type(URI), pointer :: nullURIref
456#endif
457    call check_xf(xf)
458#ifdef PGF90
459    nullURIref => null()
460#endif
461    if (xf%namespace) then
462      if (.not.checkNCName(name, xf%xds%xml_version)) &
463         call wxml_error("Invalid Name in DTD "//name)
464    else
465      if (.not.checkName(name, xf%xds%xml_version)) &
466        call wxml_error("Invalid Name in DTD "//name)
467    endif
468
469    if (present(PEDef)) then
470      if (.not.checkChars(PEDef,xf%xds%xml_version)) call wxml_error("xml_AddParameterEntity: Invalid character in PEDef")
471    endif
472
473    if (present(system)) then
474      URIref => parseURI(system)
475      if (.not.associated(URIref)) call wxml_error("xml_AddParameterEntity: Invalid SYSTEM URI")
476      call destroyURI(URIref)
477    endif
478    if (present(public)) then
479      if (.not.checkPublicId(public)) call wxml_error("xml_AddParameterEntity: Invalid PUBLIC ID")
480    endif
481
482    ! By adding a parameter entity (internal or external) we make this
483    ! a non-standalone document.
484    if (.not.xf%xds%standalone_declared) &
485      xf%xds%standalone = .false.
486
487    if (xf%state_3 == WXML_STATE_3_DURING_DTD) then
488      call add_to_buffer(" [", xf%buffer, .false.)
489      xf%state_3 = WXML_STATE_3_INSIDE_INTSUBSET
490    endif
491
492    if (xf%state_3 /= WXML_STATE_3_INSIDE_INTSUBSET) &
493      call wxml_fatal("Cannot define Parameter Entity here: "//name)
494
495    if (xf%state_2 == WXML_STATE_2_INSIDE_PI) then
496      call close_start_tag(xf)
497      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
498    endif
499
500    if (present(PEdef)) then
501      if (present(system) .or. present(public)) &
502        call wxml_fatal("Parameter entity "//name//" cannot have both a PEdef and an External ID")
503    else
504      if (.not.present(system)) &
505        call wxml_fatal("Parameter entity "//name//" must have either a PEdef or an External ID")
506    endif
507    if (present(PEdef)) then
508      if (.not.checkPEDef(PEDef, xf%xds%xml_version)) &
509        call wxml_fatal("Parameter entity definition is invalid: "//PEDef)
510      if (xf%xds%standalone) then
511        if (.not.checkExistingRefs()) &
512          call wxml_error("Tried to reference unregistered parameter entity")
513      else
514        if (.not.checkExistingRefs()) &
515          call wxml_warning(xf, "Reference to unknown parameter entity")
516      endif
517#ifdef PGF90
518      call register_internal_PE(xf%xds, name=name, text=PEdef, baseURI=nullURIref, wfc=.false.)
519#else
520      call register_internal_PE(xf%xds, name=name, text=PEdef, baseURI=null(), wfc=.false.)
521#endif
522
523    else
524#ifdef PGF90
525      call register_external_PE(xf%xds, name=name, systemId=system, &
526        publicId=public, baseURI=nullURIref, wfc=.false.)
527#else
528      call register_external_PE(xf%xds, name=name, systemId=system, &
529        publicId=public, baseURI=null(), wfc=.false.)
530#endif
531    endif
532
533    call add_eol(xf)
534
535    call add_to_buffer("<!ENTITY % "//name, xf%buffer, .false.) ! name can never contain whitespace
536    if (present(PEdef)) then
537      if (index(PEdef, """") > 0) then ! FIXME what if PEdef has both " and ' in it
538        call add_to_buffer(" '"//PEdef//"'", xf%buffer, .true.)
539      else
540        call add_to_buffer(" """//PEdef//"""", xf%buffer, .true.)
541      endif
542        call add_to_buffer(">", xf%buffer, .false.)
543    else
544      if (present(public)) then
545        call add_to_buffer(" PUBLIC", xf%buffer, .false.)
546        call add_to_buffer(" """//public//"""", xf%buffer, .true.)
547      else
548        call add_to_buffer(" SYSTEM", xf%buffer, .false.)
549      endif
550      if (scan(system, """")/=0) then
551        call add_to_buffer(" '"//system//"'", xf%buffer, .true.)
552      else
553        call add_to_buffer(" """//system//"""", xf%buffer, .true.)
554      endif
555      call add_to_buffer(">", xf%buffer)
556    endif
557
558  contains
559    function checkExistingRefs() result(p)
560      logical :: p
561
562      integer :: i1, i2
563
564      ! Here we assume we have syntactic well-formedness as
565      ! checked by checkPEDef.
566
567      p = .false.
568      i1 = index(PEDef, '%')
569      i2 = 0
570      do while (i1 > 0)
571        i1 = i2 + i1
572        i2 = index(PEDef(i1+1:),';')
573        if (i2 == 0) return
574        i2 = i1 + i2
575        if (.not.existing_entity(xf%xds%PEList, PEDef(i1+1:i2-1))) &
576          return
577        i1 = index(PEDef(i2+1:), '%')
578      enddo
579      p = .true.
580
581    end function checkExistingRefs
582#endif
583  end subroutine xml_AddParameterEntity
584
585
586  subroutine xml_AddInternalEntity(xf, name, value)
587    type(xmlf_t), intent(inout) :: xf
588    character(len=*), intent(in) :: name
589    character(len=*), intent(in) :: value
590
591#ifndef DUMMYLIB
592#ifdef PGF90
593    type(URI), pointer :: nullURI
594    nullURI => null()
595#endif
596    call check_xf(xf)
597
598    if (xf%namespace) then
599      if (.not.checkNCName(name, xf%xds%xml_version)) &
600         call wxml_error("Invalid Name in DTD "//name)
601    else
602      if (.not.checkName(name, xf%xds%xml_version)) &
603        call wxml_error("Invalid Name in DTD "//name)
604    endif
605
606    if (.not.checkChars(value, xf%xds%xml_version)) call wxml_error("xml_AddInternalEntity: Invalid character in value")
607
608    if (xf%state_3 == WXML_STATE_3_DURING_DTD) then
609      call add_to_buffer(" [", xf%buffer)
610      xf%state_3 = WXML_STATE_3_INSIDE_INTSUBSET
611    endif
612
613    if (xf%state_3 /= WXML_STATE_3_INSIDE_INTSUBSET) &
614      call wxml_fatal("Cannot define Entity here: "//name)
615
616    if (xf%state_2 == WXML_STATE_2_INSIDE_PI) then
617      call close_start_tag(xf)
618      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
619    endif
620
621    if (.not.checkName(name, xf%xds%xml_version)) &
622      call wxml_error("xml_AddInternalEntity: Invalid Name: "//name)
623#ifdef PGF90
624    call register_internal_GE(xf%xds, name=name, text=value, baseURI=nullURI, wfc=.false.)
625#else
626    call register_internal_GE(xf%xds, name=name, text=value, baseURI=null(), wfc=.false.)
627#endif
628
629    call add_eol(xf)
630
631    !FIXME - valid entity values?
632    call add_to_buffer("<!ENTITY "//name//" ", xf%buffer, .false.) ! name cannot contain whitespace
633    if (index(value, """") > 0) then
634      call add_to_buffer("'"//value//"'>", xf%buffer, .true.)
635    else
636      call add_to_buffer(""""//value//""">", xf%buffer, .true.)
637    endif
638#endif
639  end subroutine xml_AddInternalEntity
640
641
642  subroutine xml_AddExternalEntity(xf, name, system, public, notation)
643    type(xmlf_t), intent(inout) :: xf
644    character(len=*), intent(in) :: name
645    character(len=*), intent(in) :: system
646    character(len=*), intent(in), optional :: public
647    character(len=*), intent(in), optional :: notation
648
649#ifndef DUMMYLIB
650    type(URI), pointer :: URIref
651#ifdef PGF90
652    type(URI), pointer :: nullURI
653    nullURI => null()
654#endif
655    call check_xf(xf)
656
657    if (xf%namespace) then
658      if (.not.checkNCName(name, xf%xds%xml_version)) &
659         call wxml_error("Invalid Name in DTD "//name)
660    else
661      if (.not.checkName(name, xf%xds%xml_version)) &
662        call wxml_error("Invalid Name in DTD "//name)
663    endif
664    URIref => parseURI(system)
665    if (.not.associated(URIref)) call wxml_error("xml_AddExternalEntity: Invalid SYSTEM URI")
666    call destroyURI(URIref)
667    if (present(public)) then
668      if (.not.checkPublicId(public)) call wxml_error("xml_AddExternalEntity: Invalid PUBLIC ID")
669    endif
670    if (present(notation)) then
671      if (xf%namespace) then
672        if (.not.checkNCName(notation, xf%xds%xml_version)) &
673          call wxml_error("Invalid Name in DTD "//name)
674      else
675        if (.not.checkName(notation, xf%xds%xml_version)) &
676          call wxml_error("Invalid Name in DTD "//name)
677      endif
678    endif
679
680    if (xf%namespace) then
681      if (.not.checkNCName(name, xf%xds%xml_version)) &
682         call wxml_error("Invalid Name in DTD "//name)
683    else
684      if (.not.checkName(name, xf%xds%xml_version)) &
685        call wxml_error("Invalid Name in DTD "//name)
686    endif
687
688    if (xf%state_3 == WXML_STATE_3_DURING_DTD) then
689      call add_to_buffer(" [", xf%buffer, .false.)
690      xf%state_3 = WXML_STATE_3_INSIDE_INTSUBSET
691    endif
692
693    if (xf%state_3 /= WXML_STATE_3_INSIDE_INTSUBSET) &
694      call wxml_fatal("Cannot define Entity here: "//name)
695
696    if (xf%state_2 == WXML_STATE_2_INSIDE_PI) then
697      call close_start_tag(xf)
698      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
699    endif
700
701    ! Notation only needs checked if not already registered - done above.
702#ifdef PGF90
703    call register_external_GE(xf%xds, name=name, &
704      systemID=system, publicId=public, notation=notation, &
705      baseURI=nullURI, wfc=.false.)
706#else
707    call register_external_GE(xf%xds, name=name, &
708      systemID=system, publicId=public, notation=notation, &
709      baseURI=null(), wfc=.false.)
710#endif
711
712    call add_eol(xf)
713
714    call add_to_buffer("<!ENTITY "//name, xf%buffer, .false.)
715    if (present(public)) then
716      call add_to_buffer(" PUBLIC", xf%buffer, .false.)
717      call add_to_buffer(" """//public//"""", xf%buffer, .true.)
718    else
719      call add_to_buffer(" SYSTEM", xf%buffer, .false.)
720    endif
721    if (scan(system, """")/=0) then
722      call add_to_buffer(" '"//system//"'", xf%buffer, .true.)
723    else
724      call add_to_buffer(" """//system//"""", xf%buffer, .true.)
725    endif
726    if (present(notation)) then
727      call add_to_buffer(" NDATA "//notation, xf%buffer, .false.)
728    endif
729    call add_to_buffer(">", xf%buffer, .false.)
730#endif
731  end subroutine xml_AddExternalEntity
732
733
734  subroutine xml_AddNotation(xf, name, system, public)
735    type(xmlf_t), intent(inout) :: xf
736    character(len=*), intent(in) :: name
737    character(len=*), intent(in), optional :: system
738    character(len=*), intent(in), optional :: public
739
740#ifndef DUMMYLIB
741    type(URI), pointer :: URIref
742    call check_xf(xf)
743
744    if (xf%namespace) then
745      if (.not.checkNCName(name, xf%xds%xml_version)) &
746         call wxml_error("Invalid Name in DTD "//name)
747    else
748      if (.not.checkName(name, xf%xds%xml_version)) &
749        call wxml_error("Invalid Name in DTD "//name)
750    endif
751    if (present(system)) then
752      URIref => parseURI(system)
753      if (.not.associated(URIref)) call wxml_error("xml_AddNotation: Invalid SYSTEM URI")
754      call destroyURI(URIref)
755    endif
756    if (present(public)) then
757      if (.not.checkPublicId(public)) call wxml_error("xml_AddNotation: Invalid PUBLIC ID")
758    endif
759
760    if (xf%state_3 == WXML_STATE_3_DURING_DTD) then
761      call add_to_buffer(" [", xf%buffer, .false.)
762      xf%state_3 = WXML_STATE_3_INSIDE_INTSUBSET
763    endif
764
765    if (xf%state_3 /= WXML_STATE_3_INSIDE_INTSUBSET) &
766      call wxml_fatal("Cannot define Notation here: "//name)
767
768    if (xf%state_2 == WXML_STATE_2_INSIDE_PI) then
769      call close_start_tag(xf)
770      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
771    endif
772
773    if (notation_exists(xf%xds%nList, name)) &
774      call wxml_error("Tried to create duplicate notation: "//name)
775
776    call add_eol(xf)
777
778    call add_notation(xf%xds%nList, name, system, public)
779    call add_to_buffer("<!NOTATION "//name, xf%buffer, .false.)
780    if (present(public)) then
781      call add_to_buffer(" PUBLIC", xf%buffer, .false.)
782      call add_to_buffer(" """//public//"""", xf%buffer, .true.)
783    elseif (present(system)) then
784      call add_to_buffer(" SYSTEM", xf%buffer, .false.)
785    endif
786    if (present(system)) then
787      if (index(system, """") > 0) then
788        call add_to_buffer(" '"//system//"'", xf%buffer, .true.)
789      else
790        call add_to_buffer(" """//system//"""", xf%buffer, .true.)
791      endif
792    endif
793    call add_to_buffer(">", xf%buffer, .false.)
794#endif
795  end subroutine xml_AddNotation
796
797
798  subroutine xml_AddElementToDTD(xf, name, declaration)
799    type(xmlf_t), intent(inout) :: xf
800    character(len=*), intent(in) :: name
801    character(len=*), intent(in) :: declaration
802
803#ifndef DUMMYLIB
804    type(error_stack) :: stack
805#ifdef PGF90
806    type (element_t), pointer :: nullElement
807
808    nullElement => null()
809#endif
810    call check_xf(xf)
811
812    if (.not.checkChars(declaration,xf%xds%xml_version)) call wxml_error("xml_AddElementToDTD: Invalid character in declaration")
813
814    if (xf%namespace) then
815      if (.not.checkQName(name, xf%xds%xml_version)) &
816        call wxml_error("Invalid Element Name in DTD "//name)
817    else
818      if (.not.checkName(name, xf%xds%xml_version)) &
819        call wxml_error("Invalid Element Name in DTD "//name)
820    endif
821#ifdef PGF90
822    call parse_dtd_element(declaration, xf%xds%xml_version, stack, nullElement, .true.)
823#else
824    call parse_dtd_element(declaration, xf%xds%xml_version, stack, null(), .true.)
825#endif
826    if (in_error(stack)) call wxml_error(xf, "Invalid ELEMENT declaration")
827
828    if (xf%state_3 == WXML_STATE_3_DURING_DTD) then
829      call add_to_buffer(" [", xf%buffer, .false.)
830      xf%state_3 = WXML_STATE_3_INSIDE_INTSUBSET
831    endif
832
833    if (xf%state_3 /= WXML_STATE_3_INSIDE_INTSUBSET) &
834      call wxml_fatal("Cannot write to DTD here: xml_AddElementToDTD")
835
836    if (xf%state_2 == WXML_STATE_2_INSIDE_PI) then
837      call close_start_tag(xf)
838      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
839    endif
840
841    call add_eol(xf)
842    call add_to_buffer("<!ELEMENT "//name//" "//declaration//">", xf%buffer, .false.)
843#endif
844  end subroutine xml_AddElementToDTD
845
846
847  subroutine xml_AddAttlistToDTD(xf, name, declaration)
848    type(xmlf_t), intent(inout) :: xf
849    character(len=*), intent(in) :: name
850    character(len=*), intent(in) :: declaration
851
852#ifndef DUMMYLIB
853    type(error_stack) :: stack
854#ifdef PGF90
855    type (element_t), pointer :: nullElement
856
857    nullElement => null()
858#endif
859    call check_xf(xf)
860
861    if (.not.checkChars(declaration,xf%xds%xml_version)) call wxml_error("xml_AddAttListToDTD: Invalid character in declaration")
862
863    if (xf%namespace) then
864      if (.not.checkQName(name, xf%xds%xml_version)) &
865        call wxml_error("Invalid Attribute Name in DTD "//name)
866    else
867      if (.not.checkName(name, xf%xds%xml_version)) &
868        call wxml_error("Invalid Attribute Name in DTD "//name)
869    endif
870
871#ifdef PGF90
872    call parse_dtd_attlist(declaration, xf%xds%xml_version, &
873      validCheck=.false., namespaces=xf%namespace, stack=stack, &
874      elem=nullElement, internal=.true.)
875#else
876    call parse_dtd_attlist(declaration, xf%xds%xml_version, &
877      validCheck=.false., namespaces=xf%namespace, stack=stack, &
878      elem=null(), internal=.true.)
879#endif
880
881    if (in_error(stack)) call wxml_error(xf, "Invalid ATTLIST declaration")
882
883    if (xf%state_3 == WXML_STATE_3_DURING_DTD) then
884      call add_to_buffer(" [", xf%buffer, .false.)
885      xf%state_3 = WXML_STATE_3_INSIDE_INTSUBSET
886    endif
887
888    if (xf%state_3 /= WXML_STATE_3_INSIDE_INTSUBSET) &
889      call wxml_fatal("Cannot write to DTD here: xml_AddAttlistToDTD")
890
891    if (xf%state_2 == WXML_STATE_2_INSIDE_PI) then
892      call close_start_tag(xf)
893      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
894    endif
895
896    call add_eol(xf)
897    call add_to_buffer("<!ATTLIST "//name//" "//declaration//">", xf%buffer, .false.)
898#endif
899  end subroutine xml_AddAttlistToDTD
900
901
902  subroutine xml_AddPEReferenceToDTD(xf, name)
903    type(xmlf_t), intent(inout) :: xf
904    character(len=*), intent(in) :: name
905
906#ifndef DUMMYLIB
907    call check_xf(xf)
908
909    if (xf%namespace) then
910      if (.not.checkNCName(name, xf%xds%xml_version)) &
911        call wxml_error("Invalid PE Name in DTD "//name)
912    else
913      if (.not.checkName(name, xf%xds%xml_version)) &
914        call wxml_error("Invalid PE Name in DTD "//name)
915    endif
916
917    call wxml_warning(xf, "Adding PEReference to DTD. Cannot guarantee well-formedness")
918    if (.not.existing_entity(xf%xds%PEList, name)) then
919      if (.not.xf%xds%standalone) then
920        call wxml_warning(xf, "Tried to reference possibly unregistered parameter entity in DTD: "//name)
921      else
922        call wxml_error("Tried to reference unregistered parameter entity in DTD "//name)
923      endif
924    else
925      if (is_unparsed_entity(xf%xds%PEList, name)) &
926        call wxml_error("Tried to reference unparsed parameter entity in DTD "//name)
927    endif
928
929    if (xf%state_3 == WXML_STATE_3_DURING_DTD) then
930      call add_to_buffer(" [", xf%buffer, .false.)
931      xf%state_3 = WXML_STATE_3_INSIDE_INTSUBSET
932    endif
933
934    if (xf%state_3 /= WXML_STATE_3_INSIDE_INTSUBSET) &
935      call wxml_fatal("Cannot write to DTD here: xml_AddPEReferenceToDTD")
936
937    if (xf%state_2 == WXML_STATE_2_INSIDE_PI) then
938      call close_start_tag(xf)
939      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
940    endif
941
942    call add_eol(xf)
943    call add_to_buffer("%"//name//";", xf%buffer, .false.)
944
945#endif
946  end subroutine xml_AddPEReferenceToDTD
947
948
949  subroutine xml_AddXMLStylesheet(xf, href, type, title, media, charset, alternate)
950    type(xmlf_t), intent(inout)   :: xf
951    character(len=*), intent(in) :: href
952    character(len=*), intent(in) :: type
953    character(len=*), intent(in), optional :: title
954    character(len=*), intent(in), optional :: media
955    character(len=*), intent(in), optional :: charset
956    logical,          intent(in), optional :: alternate
957
958#ifndef DUMMYLIB
959    call check_xf(xf)
960    ! Don't bother checking name - all pseudoatts get checked anyway.
961
962    if (xf%state_1 /= WXML_STATE_1_JUST_OPENED &
963         .and. xf%state_1 /= WXML_STATE_1_BEFORE_ROOT) &
964      call wxml_error("Cannot add stylesheet here: "//href)
965
966    call close_start_tag(xf)
967
968    call xml_AddXMLPI(xf, 'xml-stylesheet', xml=.true.)
969    call xml_AddPseudoAttribute(xf, 'href', href)
970    call xml_AddPseudoAttribute(xf, 'type', type)
971
972    if (present(title)) call xml_AddPseudoAttribute(xf, 'title', title)
973    if (present(media)) call xml_AddPseudoAttribute(xf, 'media', media)
974    if (present(charset)) call xml_AddPseudoAttribute(xf, 'charset', charset)
975    if (present(alternate)) then
976      if (alternate) then
977        call xml_AddPseudoAttribute(xf, 'alternate', 'yes')
978      else
979        call xml_AddPseudoAttribute(xf, 'alternate', 'no')
980      endif
981    endif
982    if (xf%state_1 == WXML_STATE_1_JUST_OPENED) &
983         xf%state_1 = WXML_STATE_1_BEFORE_ROOT
984    xf%state_2 = WXML_STATE_2_INSIDE_PI
985#endif
986  end subroutine xml_AddXMLStylesheet
987
988
989  subroutine xml_AddXMLPI(xf, name, data, xml, ws_significant)
990    type(xmlf_t), intent(inout)            :: xf
991    character(len=*), intent(in)           :: name
992    character(len=*), intent(in), optional :: data
993    logical, intent(in), optional :: xml
994    logical, intent(in), optional :: ws_significant
995
996    logical :: xml_
997#ifndef DUMMYLIB
998    call check_xf(xf)
999
1000    if (present(xml)) then
1001      xml_ = xml
1002    else
1003      xml_ = .false.
1004    endif
1005
1006    if (xf%namespace) then
1007      if (.not.checkNCName(name, xf%xds%xml_version)) &
1008        call wxml_error("Invalid PI target "//name)
1009    else
1010      if (.not.checkName(name, xf%xds%xml_version)) &
1011        call wxml_error("Invalid PI target "//name)
1012    endif
1013    if (.not.xml_) then
1014      if (len(name)==3.and.(toLower(name)=="xml")) &
1015        call wxml_error("Invalid PI target "//name)
1016    endif
1017
1018    if (present(data)) then
1019      if (.not.checkChars(data,xf%xds%xml_version)) &
1020        call wxml_error("xml_AddXMLPI: Invalid character in data")
1021    endif
1022
1023    select case (xf%state_1)
1024    case (WXML_STATE_1_JUST_OPENED)
1025      xf%state_1 = WXML_STATE_1_BEFORE_ROOT
1026    case (WXML_STATE_1_DURING_ROOT)
1027      call close_start_tag(xf)
1028      if (xf%pretty_print) call add_eol(xf)
1029    case default
1030      call close_start_tag(xf)
1031      call add_eol(xf)
1032    end select
1033    call add_to_buffer("<?" // name, xf%buffer, .false.)
1034    if (present(data)) then
1035      if (len(data)>0) then
1036        if (index(data, '?>') > 0) &
1037          call wxml_error(xf, "Tried to output invalid PI data "//data)
1038        call add_to_buffer(' ', xf%buffer, .false.)
1039        call add_to_buffer(data//'?>', xf%buffer, ws_significant)
1040        ! state_2 is now OUTSIDE_TAG from close_start_tag
1041      else
1042        xf%state_2 = WXML_STATE_2_INSIDE_PI
1043        call reset_dict(xf%dict)
1044      endif
1045    else
1046      xf%state_2 = WXML_STATE_2_INSIDE_PI
1047      call reset_dict(xf%dict)
1048    endif
1049#endif
1050  end subroutine xml_AddXMLPI
1051
1052
1053  subroutine xml_AddComment(xf, comment, ws_significant)
1054    type(xmlf_t), intent(inout)   :: xf
1055    character(len=*), intent(in)  :: comment
1056    logical, intent(in), optional :: ws_significant
1057
1058#ifndef DUMMYLIB
1059    call check_xf(xf)
1060    if (.not.checkChars(comment,xf%xds%xml_version)) call wxml_error("xml_AddComment: Invalid character in comment")
1061
1062    select case (xf%state_1)
1063    case (WXML_STATE_1_JUST_OPENED)
1064      xf%state_1 = WXML_STATE_1_BEFORE_ROOT
1065    case (WXML_STATE_1_DURING_ROOT)
1066      call close_start_tag(xf)
1067      if (xf%pretty_print.and.xf%state_2 == WXML_STATE_2_OUTSIDE_TAG) call add_eol(xf)
1068    case default
1069      call close_start_tag(xf)
1070      call add_eol(xf)
1071    end select
1072
1073    if (index(comment,'--') > 0 .or. comment(len(comment):) == '-') &
1074         call wxml_error("Tried to output invalid comment "//comment)
1075
1076    call add_to_buffer("<!--", xf%buffer, .false.)
1077    call add_to_buffer(comment, xf%buffer, ws_significant)
1078    call add_to_buffer("-->", xf%buffer, .false.)
1079#endif
1080  end subroutine xml_AddComment
1081
1082
1083  subroutine xml_NewElement(xf, name)
1084    type(xmlf_t), intent(inout)   :: xf
1085    character(len=*), intent(in)  :: name
1086
1087#ifndef DUMMYLIB
1088    call check_xf(xf)
1089
1090    if (xf%namespace) then
1091      if (.not.checkQName(name, xf%xds%xml_version)) &
1092        call wxml_error("Invalid Element Name "//name)
1093    else
1094      if (.not.checkName(name, xf%xds%xml_version)) &
1095        call wxml_error("Invalid Element Name "//name)
1096    endif
1097
1098    select case (xf%state_1)
1099    case (WXML_STATE_1_JUST_OPENED, WXML_STATE_1_BEFORE_ROOT)
1100      if (xf%xds%valid) then
1101        if (size(xf%name)==0) then
1102          call wxml_error(xf, "No DTD specified for document")
1103        elseif (str_vs(xf%name) /= name) then
1104          call wxml_error(xf, "Root element name does not match DTD")
1105        endif
1106      endif
1107      call close_start_tag(xf)
1108      if (xf%state_3 /= WXML_STATE_3_BEFORE_DTD) then
1109        select case (xf%state_3)
1110        case (WXML_STATE_3_DURING_DTD)
1111          call add_to_buffer('>', xf%buffer, .false.)
1112          xf%state_3 = WXML_STATE_3_AFTER_DTD
1113        case (WXML_STATE_3_INSIDE_INTSUBSET)
1114          xf%state_3 = WXML_STATE_3_AFTER_DTD
1115          call add_eol(xf)
1116          call add_to_buffer(']>', xf%buffer, .false.)
1117        end select
1118      endif
1119      call add_eol(xf)
1120    case (WXML_STATE_1_DURING_ROOT)
1121      call close_start_tag(xf)
1122      if (xf%pretty_print) call add_eol(xf)
1123    case (WXML_STATE_1_AFTER_ROOT)
1124      call wxml_error(xf, "Two root elements: "//name)
1125    end select
1126
1127    if (xf%namespace) then
1128      if (len(prefixOfQName(name)) > 0) then
1129        if (.not.isPrefixInForce(xf%nsDict, prefixOfQName(name))) &
1130          call wxml_error(xf, "Namespace prefix not registered: "//prefixOfQName(name))
1131      endif
1132    endif
1133
1134    call push_elstack(xf%stack, name)
1135    call add_to_buffer("<"//name, xf%buffer, .false.)
1136    xf%state_2 = WXML_STATE_2_INSIDE_ELEMENT
1137    call reset_dict(xf%dict)
1138    xf%indent = xf%indent + indent_inc
1139    xf%state_1 = WXML_STATE_1_DURING_ROOT
1140#endif
1141  end subroutine xml_NewElement
1142
1143
1144  subroutine xml_AddCharacters_ch(xf, chars, parsed, ws_significant)
1145    type(xmlf_t), intent(inout)   :: xf
1146    character(len=*), intent(in)  :: chars
1147    logical, intent(in), optional :: parsed
1148    logical, intent(in), optional :: ws_significant
1149
1150#ifndef DUMMYLIB
1151    logical :: pc
1152
1153    call check_xf(xf)
1154    if (.not.checkChars(chars, xf%xds%xml_version)) call wxml_error("xml_AddCharacters: Invalid character in chars")
1155
1156    if (xf%state_1 /= WXML_STATE_1_DURING_ROOT) &
1157         call wxml_fatal("Tried to add text section in wrong place: "//chars)
1158
1159    if (present(parsed)) then
1160      pc = parsed
1161    else
1162      pc = .true.
1163    endif
1164
1165    call close_start_tag(xf)
1166
1167    if (pc) then
1168      call add_to_buffer(escape_string(chars, xf%xds%xml_version), xf%buffer, ws_significant)
1169    else
1170      ! FIXME what if we try and output two separate character events?
1171      ! need to keep track of this ...
1172      if (index(chars,']]>') > 0) &
1173           call wxml_fatal("Tried to output invalid CDATA: "//chars)
1174      call add_to_buffer("<![CDATA["//chars//"]]>", xf%buffer, ws_significant)
1175    endif
1176
1177    xf%state_2 = WXML_STATE_2_IN_CHARDATA
1178#endif
1179  end subroutine xml_AddCharacters_Ch
1180
1181
1182  subroutine xml_AddNewline(xf)
1183    type(xmlf_t), intent(inout) :: xf
1184
1185#ifndef DUMMYLIB
1186    call xml_AddCharacters(xf, "") ! To ensure we are in a text section
1187    call add_eol(xf)
1188#endif
1189  end subroutine xml_AddNewline
1190
1191
1192  subroutine xml_AddEntityReference(xf, name)
1193    type(xmlf_t), intent(inout) :: xf
1194    character(len=*), intent(in) :: name
1195
1196#ifndef DUMMYLIB
1197    call check_xf(xf)
1198
1199    if (likeCharacterEntityReference(name)) then
1200      if (.not.checkCharacterEntityReference(name, xf%xds%xml_version)) &
1201        call wxml_error("Invalid Character Entity Reference "//name)
1202    elseif (xf%namespace) then
1203      if (.not.checkNCName(name, xf%xds%xml_version)) &
1204        call wxml_error("Invalid Entity Name "//name)
1205    else
1206      if (.not.checkName(name, xf%xds%xml_version)) &
1207        call wxml_error("Invalid Entity Name "//name)
1208    endif
1209
1210    call close_start_tag(xf)
1211
1212    if (xf%state_2 /= WXML_STATE_2_OUTSIDE_TAG .and. &
1213      xf%state_2 /= WXML_STATE_2_IN_CHARDATA)         &
1214      call wxml_fatal("Tried to add entity reference in wrong place: "//name)
1215
1216    if (.not.checkCharacterEntityReference(name, xf%xds%xml_version)) then
1217      !it's not just a unicode entity
1218      call wxml_warning(xf, "Entity reference added - document may not be well-formed")
1219      if (.not.existing_entity(xf%xds%entityList, name)) then
1220        if (xf%xds%standalone) then
1221          call wxml_error("Tried to reference unregistered entity")
1222        else
1223          call wxml_warning(xf, "Tried to reference unregistered entity")
1224        endif
1225      else
1226        if (is_unparsed_entity(xf%xds%entityList, name)) &
1227          call wxml_error("Tried to reference unparsed entity")
1228      endif
1229    endif
1230
1231    call add_to_buffer('&'//name//';', xf%buffer, .false.)
1232    xf%state_2 = WXML_STATE_2_IN_CHARDATA
1233#endif
1234  end subroutine xml_AddEntityReference
1235
1236
1237  subroutine xml_AddAttribute_Ch(xf, name, value, escape, type, ws_significant)
1238    type(xmlf_t), intent(inout)             :: xf
1239    character(len=*), intent(in)            :: name
1240    character(len=*), intent(in)            :: value
1241    logical, intent(in), optional           :: escape
1242    character(len=*), intent(in), optional  :: type
1243    logical, intent(in), optional           :: ws_significant
1244
1245#ifndef DUMMYLIB
1246    logical :: esc
1247    character, pointer :: type_(:)
1248
1249    if (present(type)) then
1250      if (type/='CDATA'.and.type/='ID'.and.type/='IDREF'.and.type/='IDREFS'.and.type/='NMTOKEN'.and.type/='NMTOKENS' &
1251        .and.type/='ENTITY'.and.type/='ENTITIES'.and.type/='NOTATION') then
1252        call wxml_fatal("Invalid type in xml_AddAttribute: "//type)
1253      endif
1254      type_ => vs_str_alloc(type)
1255    else
1256      ! We assume CDATA, but need to worry about whether the caller cares about whitespace ...
1257      if (present(ws_significant)) then
1258        if (ws_significant) then
1259          type_ => vs_str_alloc('CDATA')
1260        else
1261          type_ => vs_str_alloc('CDANO') ! CDAta, whitespace Not significant
1262        endif
1263      else
1264        type_ => vs_str_alloc('CDAMB')   ! CDAta, whitespace MayBe significant
1265      endif
1266    endif
1267
1268    call check_xf(xf)
1269
1270    if (.not.checkChars(value, xf%xds%xml_version)) call wxml_error("xml_AddAttribute: Invalid character in value")
1271
1272    if (xf%namespace) then
1273      if (.not.checkQName(name, xf%xds%xml_version)) &
1274        call wxml_error("Invalid Attribute Name "//name)
1275    else
1276      if (.not.checkName(name, xf%xds%xml_version)) &
1277        call wxml_error("Invalid Attribute Name "//name)
1278    endif
1279
1280    if (present(escape)) then
1281      esc = escape
1282    else
1283      esc = .true.
1284    endif
1285
1286    if (name=="xml:space") then
1287      ! The value can only be "default" or "preserve", by 2.10
1288      if (.not.esc) then
1289        if (value/="default".and.value/="preserve") &
1290          call wxml_fatal("Invalid value for xml:space attrbute")
1291      endif
1292    endif
1293
1294    ! FIXME when escape is false we should still do full verification
1295    ! where possible.
1296    ! Currently - minimal check: only extra allowed is character entity references.
1297    ! We check they exist, and are not unparsed.
1298    ! Ideally we would fully expand all entity references (at least for
1299    ! a standalone document where we can) and then
1300    ! match the resultant production against [XML]-3.3.1. This is
1301    ! initially too much work though, so we just check simple
1302    ! syntactic constraint.
1303
1304    if (.not.esc) then
1305      if (.not.checkAttValue(value, xf%xds%xml_version)) &
1306        call wxml_error(xf, "Invalid attribute value: "//value)
1307      if (index(value, '&') > 0) then
1308        ! There are entity references
1309        ! They should exist (unless we are not standalone) and they must not be unparsed.
1310        if (.not.checkExistingRefsInAttValue()) then
1311          if (xf%xds%standalone) then
1312            call wxml_error(xf, "outputting unknown entity. Cannot guarantee validity.")
1313          else
1314            call wxml_warning(xf, "Warning: outputting unknown entity. Cannot guarantee validity.")
1315          endif
1316        endif
1317        if (.not.checkParsedRefsInAttValue()) &
1318          call wxml_error(xf, "Warning: outputting unknown entity. Cannot guarantee validity.")
1319      endif
1320    endif
1321
1322    if (xf%state_2 /= WXML_STATE_2_INSIDE_ELEMENT) &
1323         call wxml_error(xf, "attributes outside element content: "//name)
1324
1325    if (hasKey(xf%dict,name)) then
1326      call wxml_error(xf, "duplicate att name: "//name)
1327    elseif (xf%namespace) then
1328      if (hasKey(xf%dict, &
1329        getnamespaceURI(xf%nsDict,prefixOfQname(name)), localpartofQname(name))) then
1330        call wxml_error(xf, "duplicate att after namespace processing: "//name)
1331      endif
1332    endif
1333
1334    if (xf%namespace) then
1335      if (len(prefixOfQName(name))>0) then
1336        if (prefixOfQName(name)/="xml".and.prefixOfQName(name)/="xmlns") then
1337          if (.not.isPrefixInForce(xf%nsDict, prefixOfQName(name))) &
1338            call wxml_error(xf, "namespace prefix not registered: "//prefixOfQName(name))
1339        endif
1340        if (esc) then
1341          call add_item_to_dict(xf%dict, localpartofQname(name), escape_string(value, xf%xds%xml_version), prefixOfQName(name), &
1342            getnamespaceURI(xf%nsDict,prefixOfQname(name)), type=str_vs(type_))
1343        else
1344          call add_item_to_dict(xf%dict, localpartofQname(name), value, prefixOfQName(name), &
1345            getnamespaceURI(xf%nsDict,prefixOfQName(name)), type=str_vs(type_))
1346        endif
1347      else
1348        if (esc) then
1349          call add_item_to_dict(xf%dict, name, escape_string(value, xf%xds%xml_version), type=str_vs(type_))
1350        else
1351          call add_item_to_dict(xf%dict, name, value, type=str_vs(type_))
1352        endif
1353      endif
1354    else
1355      if (esc) then
1356        call add_item_to_dict(xf%dict, name, escape_string(value, xf%xds%xml_version), type=str_vs(type_))
1357      else
1358        call add_item_to_dict(xf%dict, name, value, type=str_vs(type_))
1359      endif
1360    endif
1361
1362    !FIXME need to deallocate this when we move to better error handling
1363    deallocate(type_)
1364
1365  contains
1366    function checkExistingRefsInAttValue() result(p)
1367      logical :: p
1368
1369      integer :: i1, i2
1370
1371      ! Here we assume we have syntactic well-formedness as
1372      ! checked by checkAttValue.
1373      ! We also assume we do not have simply one entity as
1374      ! the contents - that is checked by checkAttValueEntity
1375
1376      p = .false.
1377      i1 = index(value, '&')
1378      i2 = 0
1379      do while (i1 > 0)
1380        i1 = i2 + i1
1381        i2 = index(value(i1+1:),';')
1382        if (i2 == 0) return
1383        i2 = i1 + i2
1384        if (.not.existing_entity(xf%xds%entityList, value(i1+1:i2-1)) .and. &
1385          .not.checkCharacterEntityReference(value(i1+1:i2-1), xf%xds%xml_version)) &
1386          return
1387        i1 = index(value(i2+1:), '&')
1388      enddo
1389      p = .true.
1390
1391    end function checkExistingRefsInAttValue
1392
1393    function checkParsedRefsInAttValue() result(p)
1394      logical :: p
1395
1396      integer :: i1, i2
1397
1398      ! Here we assume we have syntactic well-formedness as
1399      ! checked by checkAttValue.
1400
1401      p = .false.
1402      i1 = index(value, '&')
1403      i2 = 0
1404      do while (i1 > 0)
1405        i1 = i1 + i2
1406        i2 = index(value(i1+1:),';')
1407        if (i2 == 0) return
1408        i2  = i1 + i2
1409        if (is_unparsed_entity(xf%xds%entityList, value(i1+1:i2-1))) &
1410          return
1411        i1 = index(value(i2+1:), '&')
1412      enddo
1413      p = .true.
1414
1415    end function checkParsedRefsInAttValue
1416#endif
1417  end subroutine xml_AddAttribute_Ch
1418
1419
1420  subroutine xml_AddPseudoAttribute_Ch(xf, name, value, escape, ws_significant)
1421    type(xmlf_t), intent(inout)   :: xf
1422    character(len=*), intent(in)  :: name
1423    character(len=*), intent(in)  :: value
1424    logical, intent(in), optional :: escape
1425    logical, intent(in), optional :: ws_significant
1426
1427#ifndef DUMMYLIB
1428    logical :: esc
1429    character(len=5) :: type
1430
1431    call check_xf(xf)
1432    if (.not.checkChars(name, xf%xds%xml_version)) call wxml_error("xml_AddPseudoAttribute: Invalid character in name")
1433    if (.not.checkChars(value, xf%xds%xml_version)) call wxml_error("xml_AddPseudoAttribute: Invalid character in value")
1434
1435    if (present(escape)) then
1436      esc = escape
1437    else
1438      esc = .true.
1439    endif
1440    if (present(ws_significant)) then
1441      if (ws_significant) then
1442        type='CDATA'
1443      else
1444        type='CDANO' ! CDAta, whitespace Not significant
1445      endif
1446    else
1447      type='CDAMB'   ! CDAta, whitespace MayBe significant
1448    endif
1449
1450    if (index(value, '?>') > 0) &
1451        call wxml_error(xf, "Invalid pseudo-attribute value: "//value)
1452    if (.not.esc) then
1453      if (.not.checkPseudoAttValue(value, xf%xds%xml_version)) &
1454        call wxml_error(xf, "Invalid pseudo-attribute value: "//value)
1455    endif
1456
1457    if (xf%state_2 /= WXML_STATE_2_INSIDE_PI) &
1458         call wxml_error("PI pseudo-attribute outside PI: "//name)
1459
1460    ! This is mostly ad-hoc, pseudo-attribute names are not defined anywhere.
1461    if (.not.checkName(name, xf%xds%xml_version)) &
1462         call wxml_error("Invalid pseudo-attribute name: "//name)
1463
1464    if (hasKey(xf%dict,name)) &
1465         call wxml_error(xf, "duplicate pseudo-attribute name: "//name)
1466
1467    if (index(value, '?>') > 0) &
1468         call wxml_error(xf, "Invalid pseudo-attribute data: "//value)
1469
1470    if (esc) then
1471      call add_item_to_dict(xf%dict, name, escape_string(value, xf%xds%xml_version), type=type)
1472    else
1473      call add_item_to_dict(xf%dict, name, value, type=type)
1474    endif
1475#endif
1476  end subroutine xml_AddPseudoAttribute_Ch
1477
1478
1479  subroutine xml_EndElement(xf, name)
1480    type(xmlf_t), intent(inout)             :: xf
1481    character(len=*), intent(in)            :: name
1482
1483    character :: dummy
1484#ifndef DUMMYLIB
1485    call check_xf(xf)
1486    ! No point in doing checkChars, name is compared to stack anyway.
1487
1488    if (len(xf%stack) == 0) &
1489      call wxml_fatal(xf,'Trying to close '//name//' but no tags are open.')
1490
1491    if (get_top_elstack(xf%stack) /= name) &
1492      call wxml_fatal(xf, 'Trying to close '//name//' but '//get_top_elstack(xf%stack)// &
1493      ' is open. Either you have failed to open '//name//&
1494      ' or you have failed to close '//get_top_elstack(xf%stack)//'.')
1495    xf%indent = xf%indent - indent_inc
1496
1497    if (xf%state_2==WXML_STATE_2_INSIDE_ELEMENT) then
1498      if (xf%namespace) call checkNamespacesWriting(xf%dict, xf%nsDict, len(xf%stack))
1499      if (getLength(xf%dict) > 0) call write_attributes(xf)
1500      if (xf%minimize_overrun) call add_eol(xf)
1501    endif
1502    if (xf%state_2==WXML_STATE_2_INSIDE_ELEMENT.and..not.xf%canonical) then
1503      call add_to_buffer("/>", xf%buffer, .false.)
1504    else
1505      if (xf%state_2==WXML_STATE_2_INSIDE_ELEMENT) &
1506        call add_to_buffer('>', xf%buffer, .false.)
1507      if (xf%state_2==WXML_STATE_2_INSIDE_PI) &
1508        call close_start_tag(xf)
1509      if (xf%state_2==WXML_STATE_2_OUTSIDE_TAG.and.xf%pretty_print) &
1510        call add_eol(xf)
1511! XLF does a weird thing here, and if pop_elstack is called as an
1512! argument to the add_to_buffer, it gets called twice. So we have to separate
1513! out get_top_... from pop_...
1514      call add_to_buffer("</" //get_top_elstack(xf%stack), xf%buffer, .false.)
1515      if (xf%minimize_overrun) call add_eol(xf)
1516      call add_to_buffer(">", xf%buffer, .false.)
1517    endif
1518    dummy = pop_elstack(xf%stack)
1519
1520    if (xf%namespace) call checkEndNamespaces(xf%nsDict, len(xf%stack)+1)
1521    if (is_empty(xf%stack)) then
1522      xf%state_1 = WXML_STATE_1_AFTER_ROOT
1523    endif
1524    xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
1525#endif
1526  end subroutine xml_EndElement
1527
1528
1529  subroutine xml_DeclareNamespace(xf, nsURI, prefix, xml)
1530    type(xmlf_t), intent(inout)   :: xf
1531    character(len=*), intent(in) :: nsURI
1532    character(len=*), intent(in), optional :: prefix
1533    logical, intent(in), optional :: xml
1534
1535#ifndef DUMMYLIB
1536    call check_xf(xf)
1537    if (.not.xf%namespace) call wxml_error("Cannot declare a namespace in a non-namespaced document")
1538
1539    !if (.not.checkNCName(nsURI, xf%xds%xml_version)) call wxml_error("xml_DeclareNamespace: Invalid nsURI")
1540    if (present(prefix)) then
1541      if (.not.checkNCName(prefix, xf%xds%xml_version)) call wxml_error("xml_DeclareNamespace: Invalid prefix")
1542    endif
1543
1544    if (xf%state_1 == WXML_STATE_1_AFTER_ROOT) &
1545      call wxml_error(xf, "adding namespace outside element content")
1546
1547    if (len(nsURI) == 0) then
1548      if (present(prefix).and.xf%xds%xml_version==XML1_0) &
1549        call wxml_error(xf, "prefixed namespace with empty URI forbidden in XML 1.0")
1550    endif
1551
1552    if (present(prefix)) then
1553      call addPrefixedNS(xf%nsDict, prefix, nsURI, len(xf%stack)+1, xf%xds, xml)
1554    else
1555      call addDefaultNS(xf%nsDict, nsURI, len(xf%stack)+1)
1556    endif
1557#endif
1558  end subroutine xml_DeclareNamespace
1559
1560
1561  subroutine xml_UndeclareNamespace(xf, prefix)
1562    type(xmlf_t), intent(inout)   :: xf
1563    character(len=*), intent(in), optional :: prefix
1564
1565#ifndef DUMMYLIB
1566    call check_xf(xf)
1567    !No need to checkChars, prefix is checked against stack
1568    if (.not.xf%namespace) call wxml_error("Cannot declare a namespace in a non-namespaced document")
1569
1570    if (present(prefix).and.xf%xds%xml_version==XML1_0) &
1571      call wxml_error("cannot undeclare prefixed namespaces in XML 1.0")
1572
1573    if (xf%state_1 == WXML_STATE_1_AFTER_ROOT) &
1574      call wxml_error(xf, "Undeclaring namespace outside element content")
1575
1576    if (present(prefix)) then
1577      call addPrefixedNS(xf%nsDict, prefix, "", len(xf%stack)+1, xf%xds)
1578    else
1579      call addDefaultNS(xf%nsDict, "", len(xf%stack)+1)
1580    endif
1581#endif
1582  end subroutine xml_UndeclareNamespace
1583
1584
1585  subroutine xml_Close(xf, empty)
1586    type(xmlf_t), intent(inout)   :: xf
1587    logical, optional :: empty
1588
1589#ifndef DUMMYLIB
1590    logical :: empty_
1591
1592    if (present(empty)) then
1593      empty_ = empty
1594    else
1595      empty_ = .false.
1596    endif
1597
1598    if (xf%lun == -1) &
1599      call wxml_fatal('Tried to close XML file which is not open')
1600
1601    if (xf%state_2 == WXML_STATE_2_INSIDE_PI) &
1602      call close_start_tag(xf)
1603
1604    if (xf%state_3 /= WXML_STATE_3_BEFORE_DTD &
1605      .and. xf%state_3 /= WXML_STATE_3_AFTER_DTD) then
1606      select case (xf%state_3)
1607      case (WXML_STATE_3_DURING_DTD)
1608        call add_to_buffer('>', xf%buffer, .false.)
1609      case (WXML_STATE_3_INSIDE_INTSUBSET)
1610        call add_eol(xf)
1611        call add_to_buffer(']>', xf%buffer, .false.)
1612      end select
1613      xf%state_3 = WXML_STATE_3_AFTER_DTD
1614    endif
1615
1616    do while (xf%state_1 == WXML_STATE_1_DURING_ROOT)
1617      call xml_EndElement(xf, get_top_elstack(xf%stack))
1618    enddo
1619
1620    if (xf%state_1 /= WXML_STATE_1_AFTER_ROOT) then
1621      if (empty_) then
1622        call wxml_warning(xf, 'Invalid XML document produced: No root element')
1623      else
1624        call wxml_error(xf, 'Invalid XML document produced: No root element')
1625      endif
1626    endif
1627
1628    call dump_buffer(xf%buffer)
1629    close(unit=xf%lun)
1630    xf%lun = -1
1631
1632    call destroy_dict(xf%dict)
1633    call destroy_elstack(xf%stack)
1634
1635    if (xf%namespace) &
1636      call destroyNamespaceDictionary(xf%nsDict)
1637    call destroy_xml_doc_state(xf%xds)
1638
1639    deallocate(xf%name)
1640#endif
1641  end subroutine xml_Close
1642
1643  subroutine xmlf_SetPretty_print(xf, new_value)
1644    type(xmlf_t), intent(inout) :: xf
1645    logical, intent(in)         :: new_value
1646#ifndef DUMMYLIB
1647    xf%pretty_print = new_value
1648#endif
1649  end subroutine xmlf_SetPretty_print
1650
1651  pure function xmlf_GetPretty_print(xf) result(value)
1652    logical :: value
1653    type(xmlf_t), intent(in) :: xf
1654#ifdef DUMMYLIB
1655    value = .false.
1656#else
1657    value = xf%pretty_print
1658#endif
1659  end function xmlf_GetPretty_print
1660
1661! xf%extended data is an integer so that writers
1662! can change there behaviour depending on some
1663! stored information. Currently only used for
1664! wcml 'validate' argument (which is intended to
1665! check some of the more troublesome aspects of
1666! the CML schema
1667  subroutine xmlf_SetExtendedData(xf, new_value)
1668    type(xmlf_t), intent(inout) :: xf
1669    integer, intent(in)         :: new_value
1670#ifndef DUMMYLIB
1671    xf%extended_data = new_value
1672#endif
1673  end subroutine xmlf_SetExtendedData
1674
1675  pure function xmlf_GetExtendedData(xf) result(value)
1676    integer :: value
1677    type(xmlf_t), intent(in) :: xf
1678#ifdef DUMMYLIB
1679    value = .false.
1680#else
1681    value = xf%extended_data
1682#endif
1683  end function xmlf_GetExtendedData
1684
1685  pure function xmlf_name(xf) result(fn)
1686    type (xmlf_t), intent(in) :: xf
1687#ifdef DUMMYLIB
1688    character(len=1) :: fn
1689    fn = " "
1690#else
1691    character(len=size(xf%xds%documentURI)) :: fn
1692    fn = str_vs(xf%xds%documentURI)
1693#endif
1694  end function xmlf_name
1695
1696#ifndef DUMMYLIB
1697  pure function xmlf_opentag_len(xf) result(n)
1698    type (xmlf_t), intent(in) :: xf
1699    integer :: n
1700
1701    if (xf%lun == -1) then
1702      n = 0
1703    elseif (is_empty(xf%stack)) then
1704      n = 0
1705    else
1706      n = len(get_top_elstack(xf%stack))
1707    endif
1708  end function xmlf_opentag_len
1709#endif
1710
1711  function xmlf_opentag(xf) result(fn)
1712    type (xmlf_t), intent(in) :: xf
1713#ifdef DUMMYLIB
1714    character(len=1) :: fn
1715    fn = " "
1716#else
1717    character(len=xmlf_opentag_len(xf)) :: fn
1718
1719    if (xf%lun == -1) then
1720      fn = ''
1721    elseif (is_empty(xf%stack)) then
1722      fn = ''
1723    else
1724      fn = get_top_elstack(xf%stack)
1725    endif
1726#endif
1727  end function xmlf_opentag
1728
1729#ifndef DUMMYLIB
1730
1731  subroutine check_xf(xf)
1732    type(xmlf_t), intent(inout)   :: xf
1733    if (xf%lun == -1) &
1734      call wxml_fatal("Tried to manipulate an XML File which is not open")
1735
1736  end subroutine check_xf
1737
1738
1739  subroutine add_eol(xf)
1740    type(xmlf_t), intent(inout)   :: xf
1741
1742    integer :: indent_level
1743
1744    ! In case we still have a zero-length stack, we must make
1745    ! sure indent_level is not less than zero.
1746    if (xf%state_3 == WXML_STATE_3_INSIDE_INTSUBSET) then
1747      indent_level = indent_inc
1748    else
1749      indent_level = xf%indent
1750    endif
1751
1752    !We must flush here (rather than just adding an eol character)
1753    !since we don't know what the eol character is on this system.
1754    !Flushing with a linefeed will get it automatically, though.
1755    call dump_buffer(xf%buffer, lf=.true.)
1756    call reset_buffer(xf%buffer, xf%lun, xf%xds%xml_version)
1757
1758    if (xf%pretty_print) &
1759      call add_to_buffer(repeat(' ',indent_level),xf%buffer, .false.)
1760
1761  end subroutine add_eol
1762
1763
1764  subroutine close_start_tag(xf)
1765    type(xmlf_t), intent(inout)   :: xf
1766
1767    select case (xf%state_2)
1768    case (WXML_STATE_2_INSIDE_ELEMENT)
1769      if (xf%namespace) call checkNamespacesWriting(xf%dict, xf%nsDict, len(xf%stack))
1770      if (getLength(xf%dict) > 0) call write_attributes(xf)
1771      if (xf%minimize_overrun) call add_eol(xf)
1772      call add_to_buffer('>', xf%buffer, .false.)
1773      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
1774    case (WXML_STATE_2_INSIDE_PI)
1775      if (getLength(xf%dict) > 0) call write_attributes(xf)
1776      call add_to_buffer('?>', xf%buffer, .false.)
1777      if (xf%pretty_print.and.xf%state_3/=WXML_STATE_3_INSIDE_INTSUBSET) call add_eol(xf)
1778      xf%state_2 = WXML_STATE_2_OUTSIDE_TAG
1779    case (WXML_STATE_2_IN_CHARDATA)
1780      continue
1781    case (WXML_STATE_2_OUTSIDE_TAG)
1782      continue
1783    end select
1784
1785  end subroutine close_start_tag
1786
1787
1788  subroutine write_attributes(xf)
1789    type(xmlf_t), intent(inout)   :: xf
1790
1791    integer  :: i, j, size
1792
1793    if (xf%state_2 /= WXML_STATE_2_INSIDE_PI .and. &
1794      xf%state_2 /= WXML_STATE_2_INSIDE_ELEMENT) &
1795      call wxml_fatal("Internal library error")
1796
1797    if (xf%canonical) call sortAttrs(xf%dict)
1798
1799    do i = 1, getLength(xf%dict)
1800      size = len(get_key(xf%dict, i)) + len(get_value(xf%dict, i)) + 4
1801      if (xf%minimize_overrun.and.(len(xf%buffer) + size) > COLUMNS) then
1802        call add_eol(xf)
1803      else
1804        call add_to_buffer(" ", xf%buffer, .false.)
1805      endif
1806      call add_to_buffer(get_key(xf%dict, i), xf%buffer, .false.)
1807      call add_to_buffer("=", xf%buffer, .false.)
1808      call add_to_buffer('"',xf%buffer, .false.)
1809      j = getWhiteSpaceHandling(xf%dict, i)
1810      if (j==0) then
1811        call add_to_buffer(get_value(xf%dict, i), xf%buffer, .true.)
1812      elseif (j==1) then
1813        call add_to_buffer(get_value(xf%dict, i), xf%buffer)
1814      else
1815        call add_to_buffer(get_value(xf%dict, i), xf%buffer, .false.)
1816      endif
1817      call add_to_buffer('"', xf%buffer, .false.)
1818    enddo
1819
1820  end subroutine write_attributes
1821
1822  subroutine wxml_warning_xf(xf, msg)
1823    ! Emit warning, but carry on.
1824    type(xmlf_t), intent(in) :: xf
1825    character(len=*), intent(in) :: msg
1826
1827    if (FoX_get_fatal_warnings()) then
1828        write(6,'(a)') 'FoX warning made fatal'
1829        call wxml_fatal_xf(xf, msg)
1830    endif
1831
1832    if (xf%xds%warning) then
1833      write(6,'(a)') 'WARNING(wxml) in writing to file ', xmlf_name(xf)
1834      write(6,'(a)')  msg
1835    endif
1836
1837  end subroutine wxml_warning_xf
1838
1839
1840  subroutine wxml_error_xf(xf, msg)
1841    ! Emit error message, clean up file and stop.
1842    type(xmlf_t), intent(inout) :: xf
1843    character(len=*), intent(in) :: msg
1844
1845    if (FoX_get_fatal_errors()) then
1846        write(6,'(a)') 'FoX error made fatal'
1847        call wxml_fatal_xf(xf, msg)
1848    endif
1849
1850    write(6,'(a)') 'ERROR(wxml) in writing to file ', xmlf_name(xf)
1851    write(6,'(a)')  msg
1852
1853    !call xml_Close(xf)
1854    stop
1855
1856  end subroutine wxml_error_xf
1857
1858
1859  subroutine wxml_fatal_xf(xf, msg)
1860    !Emit error message and abort with coredump. Does not try to
1861    !close file, so should be used from anything xml_Close might
1862    !itself call (to avoid infinite recursion!)
1863
1864    type(xmlf_t), intent(in) :: xf
1865    character(len=*), intent(in) :: msg
1866
1867    write(6,'(a)') 'ERROR(wxml) in writing to file ', xmlf_name(xf)
1868    write(6,'(a)')  msg
1869
1870    call pxfabort()
1871    stop
1872
1873  end subroutine wxml_fatal_xf
1874
1875#endif
1876
1877end module m_wxml_core
1878