Merge lp:~albertog/xmlf90/wxml-upgrade into lp:xmlf90
- wxml-upgrade
- Merge into trunk
Proposed by
Alberto Garcia
Status: | Merged |
---|---|
Approved by: | Alberto Garcia |
Approved revision: | 10 |
Merged at revision: | 9 |
Proposed branch: | lp:~albertog/xmlf90/wxml-upgrade |
Merge into: | lp:xmlf90 |
Diff against target: |
1492 lines (+745/-201) 11 files modified
Examples/wxml/m_pseudo_utils.f90 (+12/-11) Examples/wxml/simple.f90 (+8/-4) wxml/m_wxml_array_str.f90 (+77/-0) wxml/m_wxml_buffer.f90 (+41/-12) wxml/m_wxml_core.f90 (+220/-61) wxml/m_wxml_dictionary.f90 (+131/-62) wxml/m_wxml_elstack.f90 (+53/-23) wxml/m_wxml_overloads.f90 (+143/-0) wxml/m_wxml_text.F90 (+47/-23) wxml/makefile (+12/-2) wxml/xmlf90_wxml.f90 (+1/-3) |
To merge this branch: | bzr merge lp:~albertog/xmlf90/wxml-upgrade |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alberto Garcia | Approve | ||
Review via email: mp+284429@code.launchpad.net |
Commit message
Description of the change
Updated wxml code, brought from the libpsml distribution.
To post a comment you must log in.
lp:~albertog/xmlf90/wxml-upgrade
updated
- 10. By Alberto Garcia
-
Trim attribute values when using the overloaded interface
Attribute values can be written in the form
pi = 3.1416
call xml_AddAttribute(xf,"key" ,pi [,fmt="(f6.2)"]) which internally calls the str() function to convert
the real (or integer, etc) to a string, which is now
trimmed.
Revision history for this message
Alberto Garcia (albertog) wrote : | # |
OK. I will merge it now.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Examples/wxml/m_pseudo_utils.f90' |
2 | --- Examples/wxml/m_pseudo_utils.f90 2016-01-15 15:49:14 +0000 |
3 | +++ Examples/wxml/m_pseudo_utils.f90 2016-01-30 12:34:50 +0000 |
4 | @@ -183,7 +183,8 @@ |
5 | call xml_AddAttribute(xf,"version","0.5") |
6 | call xml_NewElement(xf,"header") |
7 | call xml_AddAttribute(xf,"symbol",trim(p%name)) |
8 | -call xml_AddAttribute(xf,"zval",trim(str(p%zval))) |
9 | +!call xml_AddAttribute(xf,"zval",trim(str(p%zval))) |
10 | +call xml_AddAttribute(xf,"zval",p%zval) ! Overloaded |
11 | call xml_AddAttribute(xf,"creator",trim(p%creator)) |
12 | call xml_AddAttribute(xf,"date",trim(p%date)) |
13 | call xml_AddAttribute(xf,"flavor",trim(p%flavor)) |
14 | @@ -206,27 +207,27 @@ |
15 | call xml_NewElement(xf,"grid") |
16 | call xml_AddAttribute(xf,"type","log") |
17 | call xml_AddAttribute(xf,"units","bohr") |
18 | - call xml_AddAttribute(xf,"scale",trim(str(p%grid_scale))) |
19 | - call xml_AddAttribute(xf,"step",trim(str(p%grid_step))) |
20 | - call xml_AddAttribute(xf,"npts",trim(str(p%nr-1))) |
21 | -call xml_EndElement(xf,"grid") |
22 | + call xml_AddAttribute(xf,"scale",p%grid_scale) |
23 | + call xml_AddAttribute(xf,"step",p%grid_step) |
24 | + call xml_AddAttribute(xf,"npts",p%nr-1) |
25 | + call xml_EndElement(xf,"grid") |
26 | |
27 | call xml_NewElement(xf,"semilocal") |
28 | |
29 | call xml_AddAttribute(xf,"units","rydberg") |
30 | call xml_AddAttribute(xf,"format","r*V") |
31 | - call xml_AddAttribute(xf,"npots-down",trim(str(p%npotd))) |
32 | - call xml_AddAttribute(xf,"npots-up",trim(str(p%npotu))) |
33 | + call xml_AddAttribute(xf,"npots-down",p%npotd) |
34 | + call xml_AddAttribute(xf,"npots-up",p%npotu) |
35 | |
36 | do i=1,p%npotd |
37 | call xml_NewElement(xf,"vps") |
38 | call xml_AddAttribute(xf,"principal-n", & |
39 | - trim(str(p%principal_n(p%ldown(i))))) |
40 | - call xml_AddAttribute(xf,"l",trim(str(p%ldown(i)))) |
41 | + p%principal_n(p%ldown(i))) |
42 | + call xml_AddAttribute(xf,"l",p%ldown(i)) |
43 | call xml_AddAttribute(xf,"cutoff", & |
44 | - trim(str(p%cutoff(p%ldown(i))))) |
45 | + p%cutoff(p%ldown(i))) |
46 | call xml_AddAttribute(xf,"occupation", & |
47 | - trim(str(p%occupation(p%ldown(i))))) |
48 | + p%occupation(p%ldown(i))) |
49 | call xml_AddAttribute(xf,"spin","-1") |
50 | |
51 | call xml_NewElement(xf,"radfunc") |
52 | |
53 | === modified file 'Examples/wxml/simple.f90' |
54 | --- Examples/wxml/simple.f90 2016-01-15 15:49:14 +0000 |
55 | +++ Examples/wxml/simple.f90 2016-01-30 12:34:50 +0000 |
56 | @@ -2,6 +2,8 @@ |
57 | |
58 | use xmlf90_wxml |
59 | |
60 | +integer, parameter :: dp = selected_real_kind(15,100) |
61 | + |
62 | type(xmlf_t) :: xf |
63 | |
64 | integer :: age = 34 |
65 | @@ -12,12 +14,14 @@ |
66 | |
67 | call xml_AddXMLDeclaration(xf,"UTF-8") |
68 | call xml_NewElement(xf,"john") |
69 | -call xml_AddAttribute(xf,"age",str(age)) |
70 | +call xml_AddAttribute(xf,"age",age) ! Overloaded int, with trimming |
71 | call xml_NewElement(xf,"peter") |
72 | +call xml_AddAttribute(xf,"with-blanks"," ..Ha.. ") ! String, no trimming |
73 | call xml_NewElement(xf,"tim") |
74 | -call xml_AddAttribute(xf,"age","37") |
75 | -call xml_AddAttribute(xf,"weight",str(123.45,"(f7.3)")) |
76 | -call xml_AddAttribute(xf,"cholesterol",str(167.0,format="(f8.0)")) |
77 | +call xml_AddAttribute(xf,"age","37") ! String, no trimming |
78 | +call xml_AddAttribute(xf,"weight",123.45_dp,fmt="(f7.3)") ! Overloaded, trimming |
79 | +call xml_AddAttribute(xf,"cholesterol",167.0,fmt="(f8.0)") ! Overloaded, trimming |
80 | +call xml_AddAttribute(xf,"realdefault",137.01) ! Overloaded, default fmt, trimming |
81 | call xml_EndElement(xf,"tim") |
82 | call xml_AddPcdata(xf,"Ping-pong") |
83 | call xml_AddPcdata(xf,"champion", line_feed=.false.) |
84 | |
85 | === added file 'wxml/m_wxml_array_str.f90' |
86 | --- wxml/m_wxml_array_str.f90 1970-01-01 00:00:00 +0000 |
87 | +++ wxml/m_wxml_array_str.f90 2016-01-30 12:34:50 +0000 |
88 | @@ -0,0 +1,77 @@ |
89 | +module m_wxml_array_str |
90 | +! |
91 | +! Utilities for character to character array |
92 | +! conversions and tests of equality. |
93 | +! |
94 | +interface operator (.equal.) |
95 | + module procedure compare_array_str |
96 | +end interface |
97 | +! |
98 | +! Not supported by all compilers... |
99 | +! interface assignment (=) |
100 | +! module procedure assign_array_to_str !!!! , assign_str_to_array |
101 | +! end interface |
102 | + |
103 | +public :: operator(.equal.) !!!! , assignment(=) |
104 | +public :: assign_array_to_str , assign_str_to_array |
105 | +private |
106 | + |
107 | +CONTAINS |
108 | +!------------------------------------------------------------- |
109 | +subroutine assign_array_to_str(str,s) |
110 | +implicit none |
111 | +character(len=1), dimension(:), intent(in) :: s |
112 | +character(len=*), intent(out) :: str |
113 | + |
114 | +integer :: i, lstr |
115 | + |
116 | +lstr = len(str) |
117 | +do i = 1, min(size(s),lstr) |
118 | + str(i:i) = s(i) |
119 | +enddo |
120 | +do i = size(s)+1, lstr |
121 | + str(i:i) = " " |
122 | +enddo |
123 | +end subroutine assign_array_to_str |
124 | + |
125 | +!------------------------------------------------------------- |
126 | +! The NAG and Intel compilers cannot distinguish this from the |
127 | +! intrinsic assignment... so we resort to using an explicit |
128 | +! subroutine call. |
129 | +! |
130 | +subroutine assign_str_to_array(s,str) |
131 | +implicit none |
132 | +character(len=1), dimension(:), intent(out) :: s |
133 | +character(len=*), intent(in) :: str |
134 | + |
135 | +integer :: i, lstr |
136 | + |
137 | +lstr = len(str) |
138 | +do i = 1, min(size(s),lstr) |
139 | + s(i) = str(i:i) |
140 | +enddo |
141 | + |
142 | +end subroutine assign_str_to_array |
143 | + |
144 | +!------------------------------------------------------------- |
145 | +function compare_array_str(s,str) result(equal) ! .equal. generic |
146 | +implicit none |
147 | +character(len=1), dimension(:), intent(in) :: s |
148 | +character(len=*), intent(in) :: str |
149 | +logical :: equal |
150 | +integer :: lens, lenstr, i |
151 | + |
152 | + |
153 | +equal = .false. |
154 | +lens = size(s) |
155 | +lenstr = len(str) |
156 | +if (lens .ne. lenstr) return |
157 | + |
158 | +do i = 1, lens |
159 | + if (s(i) .ne. str(i:i)) return |
160 | +enddo |
161 | +equal = .true. |
162 | + |
163 | +end function compare_array_str |
164 | + |
165 | +end module m_wxml_array_str |
166 | |
167 | === modified file 'wxml/m_wxml_buffer.f90' |
168 | --- wxml/m_wxml_buffer.f90 2014-09-04 09:28:10 +0000 |
169 | +++ wxml/m_wxml_buffer.f90 2016-01-30 12:34:50 +0000 |
170 | @@ -1,5 +1,9 @@ |
171 | module m_wxml_buffer |
172 | |
173 | +use m_wxml_error |
174 | + |
175 | +implicit none |
176 | + |
177 | ! |
178 | ! At this point we use a fixed-size buffer. |
179 | ! Note however that buffer overflows will only be |
180 | @@ -9,13 +13,13 @@ |
181 | ! There is code in the parser module m_fsm to avoid buffer overflows |
182 | ! caused by pcdata values. |
183 | ! |
184 | -! This module is re-used from the parser package. |
185 | +! This module is re-used from the parser package, except the size. |
186 | ! Most of the routines are superfluous at this point. |
187 | ! |
188 | ! In a forthcoming implementation it could be made dynamical... |
189 | ! |
190 | -integer, parameter, public :: MAX_BUFF_SIZE = 2000 |
191 | -integer, parameter, private :: BUFF_SIZE_WARNING = 1750 |
192 | +integer, parameter, public :: MAX_BUFF_SIZE = 10000 |
193 | +integer, parameter, private :: BUFF_SIZE_WARNING = 9500 |
194 | ! |
195 | type, public :: buffer_t |
196 | private |
197 | @@ -23,12 +27,12 @@ |
198 | character(len=MAX_BUFF_SIZE) :: str |
199 | end type buffer_t |
200 | |
201 | -public :: add_to_buffer |
202 | +public :: add_to_buffer, add_to_buffer_escaping_markup |
203 | public :: print_buffer, str, char, len |
204 | public :: operator (.equal.) |
205 | public :: buffer_nearly_full, reset_buffer |
206 | |
207 | - |
208 | +private |
209 | !---------------------------------------------------------------- |
210 | interface add_to_buffer |
211 | module procedure add_str_to_buffer |
212 | @@ -97,9 +101,7 @@ |
213 | n = buffer%size |
214 | |
215 | if (n> MAX_BUFF_SIZE) then |
216 | - stop "Buffer overflow: long unbroken string of pcdata or attribute value..." |
217 | -! RETURN |
218 | -! |
219 | + call wxml_error("Buffer overflow: long unbroken string of pcdata or attribute value...") |
220 | endif |
221 | |
222 | buffer%str(n:n) = c |
223 | @@ -110,7 +112,7 @@ |
224 | character(len=*), intent(in) :: s |
225 | type(buffer_t), intent(inout) :: buffer |
226 | |
227 | -integer :: n, len_s, last_pos |
228 | +integer :: i, n, len_s, last_pos |
229 | |
230 | len_s = len(s) |
231 | last_pos = buffer%size |
232 | @@ -118,13 +120,40 @@ |
233 | n = buffer%size |
234 | |
235 | if (n> MAX_BUFF_SIZE) then |
236 | - stop "Buffer overflow: long unbroken string of pcdata or attribute value..." |
237 | -! RETURN |
238 | + call wxml_error("Buffer overflow: long unbroken string of pcdata or attribute value...") |
239 | endif |
240 | |
241 | -buffer%str(last_pos+1:n) = s |
242 | +if (len_s.gt.0) buffer%str(last_pos+1:n) = s |
243 | end subroutine add_str_to_buffer |
244 | |
245 | +subroutine add_to_buffer_escaping_markup(s,buf) |
246 | +character(len=*), intent(in) :: s |
247 | +type(buffer_t), intent(inout) :: buf |
248 | + |
249 | +integer :: len_s, i |
250 | +character(len=1) :: c |
251 | + |
252 | +len_s = len(s) |
253 | +i = 0 |
254 | +do |
255 | + if (i==len_s) exit |
256 | + i = i + 1 |
257 | + c = s(i:i) |
258 | + if (c == "<") then |
259 | + call add_to_buffer("<",buf) |
260 | + else if (c == "&") then |
261 | + call add_to_buffer("&",buf) |
262 | + else if (c == "'") then |
263 | + call add_to_buffer("'",buf) |
264 | + else if (c == '"') then |
265 | + call add_to_buffer(""",buf) |
266 | + else |
267 | + call add_to_buffer(c,buf) |
268 | + endif |
269 | +enddo |
270 | + |
271 | +end subroutine add_to_buffer_escaping_markup |
272 | + |
273 | !---------------------------------------------------------------- |
274 | subroutine reset_buffer(buffer) |
275 | type(buffer_t), intent(inout) :: buffer |
276 | |
277 | === modified file 'wxml/m_wxml_core.f90' |
278 | --- wxml/m_wxml_core.f90 2014-09-04 09:28:10 +0000 |
279 | +++ wxml/m_wxml_core.f90 2016-01-30 12:34:50 +0000 |
280 | @@ -1,9 +1,14 @@ |
281 | module m_wxml_core |
282 | |
283 | use m_wxml_buffer |
284 | +use m_wxml_array_str, only: assign_array_to_str |
285 | +use m_wxml_array_str, only: assign_str_to_array |
286 | +use m_wxml_escape, only: check_Name |
287 | use m_wxml_elstack |
288 | use m_wxml_dictionary |
289 | |
290 | +implicit none |
291 | + |
292 | logical, private, save :: pcdata_advance_line_default = .false. |
293 | logical, private, save :: pcdata_advance_space_default = .false. |
294 | |
295 | @@ -13,19 +18,31 @@ |
296 | private |
297 | |
298 | type, public :: xmlf_t |
299 | - integer :: lun |
300 | - type(buffer_t) :: buffer |
301 | - type(elstack_t) :: stack |
302 | + character, pointer :: filename(:) |
303 | + integer :: lun |
304 | + type(buffer_t) :: buffer |
305 | + type(elstack_t) :: stack |
306 | type(wxml_dictionary_t) :: dict |
307 | - logical :: start_tag_closed |
308 | - logical :: root_element_output |
309 | - logical :: indenting_requested |
310 | + logical :: start_tag_closed |
311 | + logical :: root_element_output |
312 | + logical :: indenting_requested |
313 | + logical :: inhibit_lf |
314 | end type xmlf_t |
315 | |
316 | public :: xml_OpenFile, xml_NewElement, xml_EndElement, xml_Close |
317 | -public :: xml_AddPcdata, xml_AddAttribute, xml_AddXMLDeclaration |
318 | +public :: xml_AddXMLDeclaration |
319 | +public :: xml_AddXMLStylesheet |
320 | +public :: xml_AddXMLPI |
321 | public :: xml_AddComment, xml_AddCdataSection |
322 | - |
323 | +public :: xml_AddPcdata, xml_AddAttribute |
324 | +interface xml_AddPcdata |
325 | + module procedure xml_AddPcdata_Ch |
326 | +end interface |
327 | +! |
328 | +interface xml_AddAttribute |
329 | + module procedure xml_AddAttribute_Ch |
330 | +end interface |
331 | +! |
332 | public :: xml_AddArray |
333 | interface xml_AddArray |
334 | module procedure xml_AddArray_integer, & |
335 | @@ -37,9 +54,28 @@ |
336 | private :: add_eol |
337 | private :: write_attributes |
338 | |
339 | +!overload error handlers to allow file info |
340 | +interface wxml_warning |
341 | + module procedure wxml_warning_xf |
342 | +end interface |
343 | +interface wxml_error |
344 | + module procedure wxml_error_xf |
345 | +end interface |
346 | +interface wxml_fatal |
347 | + module procedure wxml_fatal_xf |
348 | +end interface |
349 | |
350 | +! |
351 | +! Heuristic (approximate) target for justification of output |
352 | +! Large unbroken pcdatas will go beyond this limit |
353 | +! |
354 | integer, private, parameter :: COLUMNS = 80 |
355 | |
356 | +! TOHW - This is the longest string that may be output without |
357 | +! a newline. The buffer must not be larger than this, but its size |
358 | +! can be tuned for performance. |
359 | +integer, private, parameter :: xml_recl = 4096 |
360 | + |
361 | CONTAINS |
362 | |
363 | !------------------------------------------------------------------- |
364 | @@ -50,17 +86,30 @@ |
365 | |
366 | integer :: iostat |
367 | |
368 | +allocate(xf%filename(len(filename))) |
369 | +call assign_str_to_array(xf%filename,filename) |
370 | + |
371 | call get_unit(xf%lun,iostat) |
372 | -if (iostat /= 0) stop "cannot open file" |
373 | +if (iostat /= 0) call wxml_fatal(xf, "cannot open file") |
374 | +! |
375 | +! Use large I/O buffer in case the O.S./Compiler combination |
376 | +! has hard-limits by default (i.e., NAGWare f95's 1024 byte limit) |
377 | +! This is related to the maximum size of the buffer. |
378 | +! TOHW - This is the longest string that may be output without |
379 | +! a newline. The buffer must not be larger than this, but its size |
380 | +! can be tuned for performance. |
381 | + |
382 | open(unit=xf%lun, file=filename, form="formatted", status="replace", & |
383 | - action="write", position="rewind") ! , recl=65536) |
384 | - |
385 | -call reset_elstack(xf%stack) |
386 | -call reset_dict(xf%dict) |
387 | + action="write", position="rewind", recl=xml_recl) |
388 | + |
389 | +call init_elstack(xf%stack) |
390 | + |
391 | +call init_dict(xf%dict) |
392 | call reset_buffer(xf%buffer) |
393 | |
394 | xf%start_tag_closed = .true. |
395 | xf%root_element_output = .false. |
396 | +xf%inhibit_lf = .false. |
397 | |
398 | xf%indenting_requested = .false. |
399 | if (present(indent)) then |
400 | @@ -82,6 +131,48 @@ |
401 | end subroutine xml_AddXMLDeclaration |
402 | |
403 | !------------------------------------------------------------------- |
404 | +subroutine xml_AddXMLStylesheet(xf, href, type, title, media, charset, alternate) |
405 | +type(xmlf_t), intent(inout) :: xf |
406 | +character(len=*), intent(in) :: href |
407 | +character(len=*), intent(in) :: type |
408 | +character(len=*), intent(in), optional :: title |
409 | +character(len=*), intent(in), optional :: media |
410 | +character(len=*), intent(in), optional :: charset |
411 | +logical, intent(in), optional :: alternate |
412 | + |
413 | +call add_eol(xf) |
414 | +call add_to_buffer("<?xml-stylesheet href=""" //trim(href)// & |
415 | + """ type=""" //trim(type)// """", xf%buffer) |
416 | + |
417 | +if (present(title)) call add_to_buffer(" title="""//trim(title)// """", xf%buffer) |
418 | +if (present(media)) call add_to_buffer(" media="""//trim(media)// """", xf%buffer) |
419 | +if (present(charset)) call add_to_buffer(" charset="""//trim(charset)// """", xf%buffer) |
420 | +if (present(alternate)) then |
421 | + if (alternate) then |
422 | + call add_to_buffer(" alternate=""yes""", xf%buffer) |
423 | + else |
424 | + call add_to_buffer(" alternate=""no""", xf%buffer) |
425 | + endif |
426 | +endif |
427 | +call add_to_buffer(" ?>", xf%buffer) |
428 | + |
429 | +end subroutine xml_AddXMLStylesheet |
430 | + |
431 | +!------------------------------------------------------------------- |
432 | +subroutine xml_AddXMLPI(xf, name, data) |
433 | +type(xmlf_t), intent(inout) :: xf |
434 | +character(len=*), intent(in) :: name |
435 | +character(len=*), intent(in), optional :: data |
436 | + |
437 | +call add_eol(xf) |
438 | +call add_to_buffer("<?" // trim(name) // " ", xf%buffer) |
439 | +if(present(data)) call add_to_buffer(data, xf%buffer) |
440 | +call add_to_buffer(" ?>", xf%buffer) |
441 | + |
442 | +end subroutine xml_AddXMLPI |
443 | + |
444 | + |
445 | +!------------------------------------------------------------------- |
446 | subroutine xml_AddComment(xf,comment) |
447 | type(xmlf_t), intent(inout) :: xf |
448 | character(len=*), intent(in) :: comment |
449 | @@ -94,14 +185,20 @@ |
450 | end subroutine xml_AddComment |
451 | |
452 | !------------------------------------------------------------------- |
453 | -subroutine xml_AddCdataSection(xf,cdata) |
454 | +subroutine xml_AddCdataSection(xf,cdata,line_feed) |
455 | type(xmlf_t), intent(inout) :: xf |
456 | character(len=*), intent(in) :: cdata |
457 | +logical, intent(in), optional :: line_feed |
458 | |
459 | call close_start_tag(xf,">") |
460 | +call dump_buffer(xf,line_feed) |
461 | call add_to_buffer("<![CDATA[", xf%buffer) |
462 | call add_to_buffer(cdata, xf%buffer) |
463 | call add_to_buffer("]]>", xf%buffer) |
464 | +call dump_buffer(xf,line_feed) |
465 | +if (present(line_feed)) then |
466 | + if (line_feed) xf%inhibit_lf = .true. |
467 | +endif |
468 | end subroutine xml_AddCdataSection |
469 | |
470 | !------------------------------------------------------------------- |
471 | @@ -110,10 +207,15 @@ |
472 | character(len=*), intent(in) :: name |
473 | |
474 | if (is_empty(xf%stack)) then |
475 | - if (xf%root_element_output) stop "two root elements" |
476 | + if (xf%root_element_output) call wxml_error(xf, "two root elements") |
477 | xf%root_element_output = .true. |
478 | endif |
479 | |
480 | +if (.not.check_Name(name)) then |
481 | + call wxml_warning(xf, 'attribute name '//name//' is not valid') |
482 | +endif |
483 | + |
484 | + |
485 | call close_start_tag(xf,">") |
486 | call push_elstack(name,xf%stack) |
487 | call add_eol(xf) |
488 | @@ -123,15 +225,13 @@ |
489 | |
490 | end subroutine xml_NewElement |
491 | !------------------------------------------------------------------- |
492 | -subroutine xml_AddPcdata(xf,pcdata,space,line_feed) |
493 | +subroutine xml_AddPcdata_Ch(xf,pcdata,space,line_feed) |
494 | type(xmlf_t), intent(inout) :: xf |
495 | character(len=*), intent(in) :: pcdata |
496 | logical, intent(in), optional :: space |
497 | logical, intent(in), optional :: line_feed |
498 | |
499 | logical :: advance_line , advance_space |
500 | -integer :: n, i, jmax |
501 | -integer, parameter :: chunk_size = 128 |
502 | |
503 | advance_line = pcdata_advance_line_default |
504 | if (present(line_feed)) then |
505 | @@ -144,7 +244,7 @@ |
506 | endif |
507 | |
508 | if (is_empty(xf%stack)) then |
509 | - stop "pcdata outside element content" |
510 | + call wxml_error(xf, "pcdata outside element content") |
511 | endif |
512 | |
513 | call close_start_tag(xf,">") |
514 | @@ -161,43 +261,32 @@ |
515 | endif |
516 | endif |
517 | if (advance_space) call add_to_buffer(" ",xf%buffer) |
518 | -if (len(xf%buffer) > 0) call dump_buffer(xf,lf=.false.) |
519 | -! |
520 | -! We bypass the buffer for the bulk of the dump |
521 | -! |
522 | -n = len(pcdata) |
523 | -!print *, "writing pcdata of length: ", n |
524 | -i = 1 |
525 | -do |
526 | - jmax = min(i+chunk_size-1,n) |
527 | -! print *, "writing chunk: ", i, jmax |
528 | - write(unit=xf%lun,fmt="(a)",advance="no") pcdata(i:jmax) |
529 | - if (jmax == n) exit |
530 | - i = jmax + 1 |
531 | -enddo |
532 | -end subroutine xml_AddPcdata |
533 | + |
534 | +call add_to_buffer_escaping_markup(pcdata, xf%buffer) |
535 | + |
536 | +end subroutine xml_AddPcdata_Ch |
537 | |
538 | !------------------------------------------------------------------- |
539 | -subroutine xml_AddAttribute(xf,name,value) |
540 | +subroutine xml_AddAttribute_Ch(xf,name,value) |
541 | type(xmlf_t), intent(inout) :: xf |
542 | character(len=*), intent(in) :: name |
543 | character(len=*), intent(in) :: value |
544 | |
545 | if (is_empty(xf%stack)) then |
546 | - stop "attributes outside element content" |
547 | + call wxml_error(xf, "attributes outside element content") |
548 | endif |
549 | |
550 | if (xf%start_tag_closed) then |
551 | - stop "attributes outside start tag" |
552 | + call wxml_error(xf, "attributes outside start tag") |
553 | endif |
554 | + |
555 | if (has_key(xf%dict,name)) then |
556 | - stop "duplicate att name" |
557 | + call wxml_error(xf, "duplicate att name") |
558 | endif |
559 | |
560 | -call add_key_to_dict(trim(name),xf%dict) |
561 | -call add_value_to_dict(trim(value),xf%dict) |
562 | +call add_item_to_dict(xf%dict, name, value) |
563 | |
564 | -end subroutine xml_AddAttribute |
565 | +end subroutine xml_AddAttribute_Ch |
566 | |
567 | !----------------------------------------------------------- |
568 | subroutine xml_EndElement(xf,name) |
569 | @@ -207,19 +296,19 @@ |
570 | character(len=100) :: current |
571 | |
572 | if (is_empty(xf%stack)) then |
573 | - stop "Out of elements to close" |
574 | + call wxml_fatal(xf, "Out of elements to close") |
575 | endif |
576 | |
577 | call get_top_elstack(xf%stack,current) |
578 | if (current /= name) then |
579 | - print *, "current, name: ", trim(current), " ", trim(name) |
580 | - stop |
581 | + call wxml_fatal(xf, 'Trying to close '//Trim(name)//' but '//Trim(current)//' is open.') |
582 | endif |
583 | if (.not. xf%start_tag_closed) then ! Empty element |
584 | if (len(xf%dict) > 0) call write_attributes(xf) |
585 | call add_to_buffer(" />",xf%buffer) |
586 | xf%start_tag_closed = .true. |
587 | else |
588 | + ! This statement will introduce a newline after array data... |
589 | call add_eol(xf) |
590 | call add_to_buffer("</" // trim(name) // ">", xf%buffer) |
591 | endif |
592 | @@ -230,11 +319,21 @@ |
593 | !---------------------------------------------------------------- |
594 | |
595 | subroutine xml_Close(xf) |
596 | -type(xmlf_t), intent(in) :: xf |
597 | +type(xmlf_t), intent(inout) :: xf |
598 | + |
599 | +character(len=200) :: name |
600 | + |
601 | +do |
602 | + if (is_empty(xf%stack)) exit |
603 | + call get_top_elstack(xf%stack,name) |
604 | + call xml_EndElement(xf,trim(name)) |
605 | +enddo |
606 | |
607 | write(unit=xf%lun,fmt="(a)") char(xf%buffer) |
608 | close(unit=xf%lun) |
609 | |
610 | +deallocate(xf%filename) |
611 | + |
612 | end subroutine xml_Close |
613 | |
614 | !================================================================== |
615 | @@ -266,14 +365,24 @@ |
616 | type(xmlf_t), intent(inout) :: xf |
617 | |
618 | integer :: indent_level |
619 | -character(len=100), parameter :: blanks = "" |
620 | - |
621 | -indent_level = len(xf%stack) - 1 |
622 | -write(unit=xf%lun,fmt="(a)") char(xf%buffer) |
623 | -call reset_buffer(xf%buffer) |
624 | - |
625 | + |
626 | + |
627 | +! Flush with a linefeed except if a previous operation has raised |
628 | +! the inhibit_lf flag |
629 | + |
630 | +if (xf%inhibit_lf) then |
631 | + call dump_buffer(xf,lf=.false.) |
632 | + xf%inhibit_lf = .false. |
633 | +else |
634 | + call dump_buffer(xf,lf=.true.) |
635 | +endif |
636 | + |
637 | +! In case we still have a zero-length stack, we must make |
638 | +! sure indent_level is not less than zero. |
639 | + |
640 | +indent_level = max(len(xf%stack) - 1, 0) |
641 | if (xf%indenting_requested) & |
642 | - call add_to_buffer(blanks(1:indent_level),xf%buffer) |
643 | + call add_to_buffer(repeat(' ',indent_level),xf%buffer) |
644 | |
645 | end subroutine add_eol |
646 | !------------------------------------------------------------ |
647 | @@ -311,21 +420,19 @@ |
648 | subroutine write_attributes(xf) |
649 | type(xmlf_t), intent(inout) :: xf |
650 | |
651 | -integer :: i, status, size |
652 | -character(len=100) :: key, value |
653 | +integer :: i, status, size, key_len, value_len |
654 | +character(len=200) :: key, value |
655 | |
656 | do i = 1, len(xf%dict) |
657 | - call get_key(xf%dict,i,key,status) |
658 | - call get_value(xf%dict,key,value,status) |
659 | - key = adjustl(key) |
660 | - value = adjustl(value) |
661 | - size = len_trim(key) + len_trim(value) + 4 |
662 | + call get_key(xf%dict,i,key,key_len,status) |
663 | + call get_value(xf%dict,i,value,value_len,status) |
664 | + size = key_len + value_len + 4 |
665 | if ((len(xf%buffer) + size) > COLUMNS) call add_eol(xf) |
666 | call add_to_buffer(" ", xf%buffer) |
667 | - call add_to_buffer(trim(key), xf%buffer) |
668 | + call add_to_buffer(key(:key_len), xf%buffer) |
669 | call add_to_buffer("=", xf%buffer) |
670 | call add_to_buffer("""",xf%buffer) |
671 | - call add_to_buffer(trim(value), xf%buffer) |
672 | + call add_to_buffer_escaping_markup(value(:value_len), xf%buffer) |
673 | call add_to_buffer("""", xf%buffer) |
674 | enddo |
675 | |
676 | @@ -343,6 +450,7 @@ |
677 | write(xf%lun,format) a |
678 | else |
679 | write(xf%lun,"(6(i12))") a |
680 | + xf%inhibit_lf = .true. |
681 | endif |
682 | end subroutine xml_AddArray_integer |
683 | |
684 | @@ -359,6 +467,7 @@ |
685 | else |
686 | write(xf%lun,"(4(es20.12))") a |
687 | endif |
688 | + xf%inhibit_lf = .true. |
689 | end subroutine xml_AddArray_real_dp |
690 | |
691 | !------------------------------------------------------------------ |
692 | @@ -374,7 +483,57 @@ |
693 | else |
694 | write(xf%lun,"(4(es20.12))") a |
695 | endif |
696 | + xf%inhibit_lf = .true. |
697 | end subroutine xml_AddArray_real_sp |
698 | |
699 | +!--------------------------------------------------------- |
700 | +! Error handling/trapping routines: |
701 | + |
702 | + subroutine wxml_warning_xf(xf, msg) |
703 | + ! Emit warning, but carry on. |
704 | + type(xmlf_t), intent(in) :: xf |
705 | + character(len=*), intent(in) :: msg |
706 | + |
707 | + write(6,'(a)') 'WARNING(wxml) in writing to file ', xmlf_name(xf) |
708 | + write(6,'(a)') msg |
709 | + |
710 | + end subroutine wxml_warning_xf |
711 | + |
712 | + subroutine wxml_error_xf(xf, msg) |
713 | + ! Emit error message, clean up file and stop. |
714 | + type(xmlf_t), intent(inout) :: xf |
715 | + character(len=*), intent(in) :: msg |
716 | + |
717 | + write(6,'(a)') 'ERROR(wxml) in writing to file ', xmlf_name(xf) |
718 | + write(6,'(a)') msg |
719 | + |
720 | + call xml_Close(xf) |
721 | + stop |
722 | + |
723 | + end subroutine wxml_error_xf |
724 | + |
725 | + subroutine wxml_fatal_xf(xf, msg) |
726 | + !Emit error message and abort with coredump. Does not try to |
727 | + !close file, so should be used from anything xml_Close might |
728 | + !itself call (to avoid infinite recursion!) |
729 | + |
730 | + type(xmlf_t), intent(in) :: xf |
731 | + character(len=*), intent(in) :: msg |
732 | + |
733 | + write(6,'(a)') 'ERROR(wxml) in writing to file ', xmlf_name(xf) |
734 | + write(6,'(a)') msg |
735 | + |
736 | + !call pxfabort |
737 | + stop |
738 | + |
739 | + end subroutine wxml_fatal_xf |
740 | + |
741 | + function xmlf_name(xf) result(fn) |
742 | + Type (xmlf_t), intent(in) :: xf |
743 | + character(len=size(xf%filename)) :: fn |
744 | + call assign_array_to_str(fn,xf%filename) |
745 | + end function xmlf_name |
746 | + |
747 | + |
748 | end module m_wxml_core |
749 | |
750 | |
751 | === modified file 'wxml/m_wxml_dictionary.f90' |
752 | --- wxml/m_wxml_dictionary.f90 2014-09-04 09:28:10 +0000 |
753 | +++ wxml/m_wxml_dictionary.f90 2016-01-30 12:34:50 +0000 |
754 | @@ -1,24 +1,32 @@ |
755 | module m_wxml_dictionary |
756 | |
757 | + use m_wxml_escape, only : check_Name |
758 | + use m_wxml_error, only : wxml_fatal |
759 | + use m_wxml_array_str |
760 | + |
761 | + implicit none |
762 | + |
763 | private |
764 | ! |
765 | -! A very rough implementation for now |
766 | -! It uses fixed-length buffers for key/value pairs, |
767 | -! and the maximum number of dictionary items is hardwired. |
768 | - |
769 | integer, parameter, private :: MAX_ITEMS = 30 |
770 | + |
771 | +type, private :: dict_item |
772 | + character(len=1), pointer, dimension(:) :: key |
773 | + character(len=1), pointer, dimension(:) :: value |
774 | +end type dict_item |
775 | + |
776 | type, public :: wxml_dictionary_t |
777 | private |
778 | integer :: number_of_items ! = 0 |
779 | - character(len=100), dimension(MAX_ITEMS) :: key |
780 | - character(len=100), dimension(MAX_ITEMS) :: value |
781 | + type(dict_item), dimension(MAX_ITEMS) :: items |
782 | end type wxml_dictionary_t |
783 | |
784 | ! |
785 | ! Building procedures |
786 | ! |
787 | -public :: add_key_to_dict, add_value_to_dict, reset_dict |
788 | - |
789 | +public :: init_dict |
790 | +public :: reset_dict |
791 | +public :: add_item_to_dict |
792 | ! |
793 | ! Query and extraction procedures |
794 | ! |
795 | @@ -27,13 +35,13 @@ |
796 | module procedure number_of_entries |
797 | end interface |
798 | public :: number_of_entries |
799 | -public :: get_key |
800 | +public :: get_key |
801 | public :: get_value |
802 | public :: has_key |
803 | public :: print_dict |
804 | ! |
805 | interface get_value |
806 | - module procedure wxml_get_value |
807 | + module procedure wxml_get_value, wxml_get_value_i |
808 | end interface |
809 | |
810 | CONTAINS |
811 | @@ -53,14 +61,13 @@ |
812 | character(len=*), intent(in) :: key |
813 | logical :: found |
814 | |
815 | -integer :: n, i |
816 | +integer :: i |
817 | found = .false. |
818 | -n = dict%number_of_items |
819 | -do i = 1, n |
820 | - if (dict%key(i) == key) then |
821 | - found = .true. |
822 | - exit |
823 | - endif |
824 | +do i = 1, dict%number_of_items |
825 | + if (dict%items(i)%key .equal. key) then |
826 | + found = .true. |
827 | + exit |
828 | + endif |
829 | enddo |
830 | end function has_key |
831 | |
832 | @@ -71,79 +78,141 @@ |
833 | character(len=*), intent(out) :: value |
834 | integer, intent(out) :: status |
835 | ! |
836 | -integer :: n, i |
837 | +integer :: i |
838 | |
839 | status = -1 |
840 | -n = dict%number_of_items |
841 | -do i = 1, n |
842 | - if (dict%key(i) == key) then |
843 | - value = dict%value(i) |
844 | - status = 0 |
845 | - RETURN |
846 | - endif |
847 | +do i = 1, dict%number_of_items |
848 | + if (dict%items(i)%key .equal. key) then |
849 | + call assign_array_to_str(value,dict%items(i)%value) |
850 | + status = 0 |
851 | + exit |
852 | + endif |
853 | enddo |
854 | |
855 | end subroutine wxml_get_value |
856 | |
857 | +function get_value_len(dict, key) result(value_len) |
858 | + type(wxml_dictionary_t), intent(in) :: dict |
859 | + character(len=*), intent(in) :: key |
860 | + integer :: value_len |
861 | + |
862 | + integer :: i |
863 | + |
864 | + value_len = 0 |
865 | + do i = 1, dict%number_of_items |
866 | + if (dict%items(i)%key .equal. key) then |
867 | + value_len = size(dict%items(i)%value) |
868 | + exit |
869 | + endif |
870 | + enddo |
871 | + |
872 | +end function get_value_len |
873 | + |
874 | + |
875 | !------------------------------------------------------ |
876 | -subroutine get_key(dict,i,key,status) |
877 | +subroutine get_key(dict,i,key,key_len,status) |
878 | ! |
879 | ! Get the i'th key |
880 | ! |
881 | type(wxml_dictionary_t), intent(in) :: dict |
882 | integer, intent(in) :: i |
883 | character(len=*), intent(out) :: key |
884 | +integer, intent(out) :: key_len |
885 | integer, intent(out) :: status |
886 | |
887 | -if (i <= dict%number_of_items) then |
888 | - key = dict%key(i) |
889 | +if (i>0 .and. i<=dict%number_of_items) then |
890 | + call assign_array_to_str(key,dict%items(i)%key) |
891 | + key_len = size(dict%items(i)%key) |
892 | status = 0 |
893 | else |
894 | - key = "" |
895 | + key = ' ' |
896 | + key_len = 0 |
897 | status = -1 |
898 | endif |
899 | |
900 | end subroutine get_key |
901 | - |
902 | !------------------------------------------------------ |
903 | -subroutine add_key_to_dict(key,dict) |
904 | -character(len=*), intent(in) :: key |
905 | -type(wxml_dictionary_t), intent(inout) :: dict |
906 | - |
907 | -integer :: n |
908 | - |
909 | -n = dict%number_of_items |
910 | -if (n == MAX_ITEMS) then |
911 | - write(unit=0,fmt=*) "Dictionary capacity exceeded !" |
912 | - RETURN |
913 | +subroutine wxml_get_value_i(dict,i,value,value_len,status) |
914 | +! |
915 | +! Get the i'th value |
916 | +! |
917 | +type(wxml_dictionary_t), intent(in) :: dict |
918 | +integer, intent(in) :: i |
919 | +character(len=*), intent(out) :: value |
920 | +integer, intent(out) :: value_len |
921 | +integer, intent(out) :: status |
922 | + |
923 | +if (i>0 .and. i<=dict%number_of_items) then |
924 | + call assign_array_to_str(value,dict%items(i)%value) |
925 | + value_len = size(dict%items(i)%value) |
926 | + status = 0 |
927 | +else |
928 | + value = ' ' |
929 | + value_len = 0 |
930 | + status = -1 |
931 | endif |
932 | |
933 | -n = n + 1 |
934 | -dict%key(n) = key |
935 | -dict%number_of_items = n |
936 | - |
937 | -end subroutine add_key_to_dict |
938 | +end subroutine wxml_get_value_i |
939 | + |
940 | +subroutine add_item_to_dict(dict, key, value) |
941 | + |
942 | + type(wxml_dictionary_t), intent(inout) :: dict |
943 | + character(len=*), intent(in) :: key |
944 | + character(len=*), intent(in) :: value |
945 | + |
946 | + character(len=len(key)) :: check_key |
947 | + integer :: n, lenstr |
948 | + |
949 | + n = dict%number_of_items |
950 | + if (n == MAX_ITEMS) then |
951 | + write(unit=0,fmt=*) "Dictionary capacity exceeded !" |
952 | + RETURN |
953 | + endif |
954 | + |
955 | +! keys may not have initial (or trailing; thus trim below) blanks: |
956 | +!TOHW remove this check? shouldn't be passing blank-prefixed strings anyway. |
957 | + check_key=adjustl(key) |
958 | + if (.not.check_Name(trim(check_key))) then |
959 | + call wxml_fatal('attribute name is invalid') |
960 | + endif |
961 | + |
962 | + n = n + 1 |
963 | + lenstr=len_trim(check_key) |
964 | + allocate(dict%items(n)%key(lenstr)) |
965 | + call assign_str_to_array(dict%items(n)%key,check_key) |
966 | + allocate(dict%items(n)%value(len(value))) |
967 | + call assign_str_to_array(dict%items(n)%value,value) |
968 | + |
969 | + dict%number_of_items = n |
970 | + |
971 | +end subroutine add_item_to_dict |
972 | |
973 | !------------------------------------------------------ |
974 | -! Assumes we build the dictionary in an orderly fashion, |
975 | -! so one adds first the key and then immediately afterwards the value. |
976 | -! |
977 | -subroutine add_value_to_dict(value,dict) |
978 | -character(len=*), intent(in) :: value |
979 | -type(wxml_dictionary_t), intent(inout) :: dict |
980 | - |
981 | -integer :: n |
982 | - |
983 | -n = dict%number_of_items |
984 | -dict%value(n) = value |
985 | - |
986 | -end subroutine add_value_to_dict |
987 | - |
988 | +subroutine init_dict(dict) |
989 | + type(wxml_dictionary_t), intent(out) :: dict |
990 | + |
991 | + integer :: i |
992 | + |
993 | + do i = 1, MAX_ITEMS |
994 | + nullify(dict%items(i)%key) |
995 | + nullify(dict%items(i)%key) |
996 | + enddo |
997 | + |
998 | + dict % number_of_items = 0 |
999 | + |
1000 | +end subroutine init_dict |
1001 | + |
1002 | !------------------------------------------------------ |
1003 | subroutine reset_dict(dict) |
1004 | -type(wxml_dictionary_t), intent(inout) :: dict |
1005 | + type(wxml_dictionary_t), intent(inout) :: dict |
1006 | + |
1007 | + integer :: i |
1008 | + do i = 1, dict%number_of_items |
1009 | + deallocate(dict%items(i)%key) |
1010 | + deallocate(dict%items(i)%value) |
1011 | + enddo |
1012 | |
1013 | -dict%number_of_items = 0 |
1014 | + dict%number_of_items = 0 |
1015 | |
1016 | end subroutine reset_dict |
1017 | |
1018 | @@ -154,7 +223,7 @@ |
1019 | integer :: i |
1020 | |
1021 | do i = 1, dict%number_of_items |
1022 | - print *, trim(dict%key(i)), " = ", trim(dict%value(i)) |
1023 | + print *, dict%items(i)%key, " = ", dict%items(i)%value |
1024 | enddo |
1025 | |
1026 | end subroutine print_dict |
1027 | |
1028 | === modified file 'wxml/m_wxml_elstack.f90' |
1029 | --- wxml/m_wxml_elstack.f90 2014-09-04 09:28:10 +0000 |
1030 | +++ wxml/m_wxml_elstack.f90 2016-01-30 12:34:50 +0000 |
1031 | @@ -1,19 +1,30 @@ |
1032 | module m_wxml_elstack |
1033 | |
1034 | +use m_wxml_error |
1035 | + |
1036 | +implicit none |
1037 | + |
1038 | private |
1039 | |
1040 | ! |
1041 | ! Simple stack to keep track of which elements have appeared so far |
1042 | ! |
1043 | -integer, parameter, private :: STACK_SIZE = 20 |
1044 | +! Initial stack size: |
1045 | +integer, parameter, private :: STACK_SIZE_INIT = 10 |
1046 | +! Multiplier when stack is exceeded: |
1047 | +real, parameter, private :: STACK_SIZE_MULT = 1.5 |
1048 | + |
1049 | +type, private :: elstack_item |
1050 | + character(len=100) :: data |
1051 | +end type |
1052 | |
1053 | type, public :: elstack_t |
1054 | private |
1055 | - integer :: n_items |
1056 | - character(len=100), dimension(STACK_SIZE) :: data |
1057 | + integer :: n_items |
1058 | + type(elstack_item), pointer, dimension(:) :: stack |
1059 | end type elstack_t |
1060 | |
1061 | -public :: push_elstack, pop_elstack, reset_elstack, print_elstack |
1062 | +public :: push_elstack, pop_elstack, init_elstack, reset_elstack, print_elstack |
1063 | public :: get_top_elstack, is_empty, get_elstack_signature |
1064 | public :: len |
1065 | |
1066 | @@ -30,14 +41,39 @@ |
1067 | CONTAINS |
1068 | |
1069 | !----------------------------------------------------------------- |
1070 | +subroutine init_elstack(elstack) |
1071 | + type(elstack_t), intent(inout) :: elstack |
1072 | + |
1073 | + allocate(elstack%stack(STACK_SIZE_INIT)) |
1074 | + elstack%n_items = 0 |
1075 | + |
1076 | +end subroutine init_elstack |
1077 | + |
1078 | +!----------------------------------------------------------------- |
1079 | subroutine reset_elstack(elstack) |
1080 | -type(elstack_t), intent(inout) :: elstack |
1081 | + type(elstack_t), intent(inout) :: elstack |
1082 | |
1083 | -elstack%n_items = 0 |
1084 | + deallocate(elstack%stack) |
1085 | + call init_elstack(elstack) |
1086 | |
1087 | end subroutine reset_elstack |
1088 | |
1089 | !----------------------------------------------------------------- |
1090 | +subroutine resize_elstack(elstack) |
1091 | + type(elstack_t), intent(inout) :: elstack |
1092 | + type(elstack_item), pointer, dimension(:) :: temp |
1093 | + integer :: s |
1094 | + |
1095 | + s = size(elstack%stack) |
1096 | + |
1097 | + temp=>elstack%stack |
1098 | + allocate(elstack%stack(nint(s*STACK_SIZE_MULT))) |
1099 | + elstack%stack(:s) = temp |
1100 | + deallocate(temp) |
1101 | + |
1102 | +end subroutine resize_elstack |
1103 | + |
1104 | +!----------------------------------------------------------------- |
1105 | function is_empty_elstack(elstack) result(answer) |
1106 | type(elstack_t), intent(in) :: elstack |
1107 | logical :: answer |
1108 | @@ -61,11 +97,11 @@ |
1109 | integer :: n |
1110 | |
1111 | n = elstack%n_items |
1112 | -if (n == STACK_SIZE) then |
1113 | - stop "*Element stack full" |
1114 | +if (n == size(elstack%stack)) then |
1115 | + call resize_elstack(elstack) |
1116 | endif |
1117 | n = n + 1 |
1118 | -elstack%data(n) = item |
1119 | +elstack%stack(n)%data = item |
1120 | elstack%n_items = n |
1121 | |
1122 | end subroutine push_elstack |
1123 | @@ -75,16 +111,13 @@ |
1124 | type(elstack_t), intent(inout) :: elstack |
1125 | character(len=*), intent(out) :: item |
1126 | |
1127 | -! |
1128 | -! We assume the elstack is not empty... (the user has called is_empty first) |
1129 | -! |
1130 | integer :: n |
1131 | |
1132 | n = elstack%n_items |
1133 | if (n == 0) then |
1134 | - stop "*********Element stack empty" |
1135 | + call wxml_error("Element stack empty") |
1136 | endif |
1137 | -item = elstack%data(n) |
1138 | +item = elstack%stack(n)%data |
1139 | elstack%n_items = n - 1 |
1140 | |
1141 | end subroutine pop_elstack |
1142 | @@ -97,16 +130,13 @@ |
1143 | type(elstack_t), intent(in) :: elstack |
1144 | character(len=*), intent(out) :: item |
1145 | |
1146 | -! |
1147 | -! We assume the elstack is not empty... (the user has called is_empty first) |
1148 | -! |
1149 | integer :: n |
1150 | |
1151 | n = elstack%n_items |
1152 | if (n == 0) then |
1153 | - stop "*********Element stack empty" |
1154 | + call wxml_error("Element stack empty") |
1155 | endif |
1156 | -item = elstack%data(n) |
1157 | +item = elstack%stack(n)%data |
1158 | |
1159 | end subroutine get_top_elstack |
1160 | |
1161 | @@ -117,7 +147,7 @@ |
1162 | integer :: i |
1163 | |
1164 | do i = elstack%n_items, 1, -1 |
1165 | - write(unit=unit,fmt=*) trim(elstack%data(i)) |
1166 | + write(unit=unit,fmt=*) trim(elstack%stack(i)%data) |
1167 | enddo |
1168 | |
1169 | end subroutine print_elstack |
1170 | @@ -128,13 +158,13 @@ |
1171 | character(len=*), intent(out) :: string |
1172 | integer :: i, length, j |
1173 | |
1174 | -string = "" |
1175 | +string = ' ' |
1176 | j = 0 |
1177 | do i = 1, elstack%n_items |
1178 | - length = len_trim(elstack%data(i)) |
1179 | + length = len_trim(elstack%stack(i)%data) |
1180 | string(j+1:j+1) = "/" |
1181 | j = j+1 |
1182 | - string(j+1:j+length) = trim(elstack%data(i)) |
1183 | + string(j+1:j+length) = trim(elstack%stack(i)%data) |
1184 | j = j + length |
1185 | enddo |
1186 | |
1187 | |
1188 | === added file 'wxml/m_wxml_overloads.f90' |
1189 | --- wxml/m_wxml_overloads.f90 1970-01-01 00:00:00 +0000 |
1190 | +++ wxml/m_wxml_overloads.f90 2016-01-30 12:34:50 +0000 |
1191 | @@ -0,0 +1,143 @@ |
1192 | +module m_wxml_overloads |
1193 | + |
1194 | + use m_wxml_text, only: str |
1195 | + use m_wxml_core, only: xmlf_t |
1196 | + use m_wxml_core, only: xml_AddPcData_Ch => xml_AddPcData |
1197 | + use m_wxml_core, only: xml_AddAttribute_Ch => xml_AddAttribute |
1198 | + |
1199 | + implicit none |
1200 | + |
1201 | + integer, parameter :: sp = selected_real_kind(6,30) |
1202 | + integer, parameter :: dp = selected_real_kind(14,100) |
1203 | + |
1204 | + private |
1205 | + |
1206 | + public :: xml_AddPcdata |
1207 | + public :: xml_AddAttribute |
1208 | + |
1209 | + interface xml_AddPcData |
1210 | + module procedure xml_AddPcdata_SP |
1211 | + module procedure xml_AddPcdata_DP |
1212 | + module procedure xml_AddPcdata_Int |
1213 | + module procedure xml_AddPcdata_Log |
1214 | + end interface |
1215 | + |
1216 | + interface xml_AddAttribute |
1217 | + module procedure xml_AddAttribute_SP |
1218 | + module procedure xml_AddAttribute_DP |
1219 | + module procedure xml_AddAttribute_Int |
1220 | + module procedure xml_AddAttribute_Log |
1221 | + end interface |
1222 | + |
1223 | +CONTAINS |
1224 | + |
1225 | + !------------------------------------------------------------------- |
1226 | + |
1227 | + subroutine xml_AddPcdata_SP(xf,pcdata,fmt, space,line_feed) |
1228 | + type(xmlf_t), intent(inout) :: xf |
1229 | + real(kind=sp), intent(in) :: pcdata |
1230 | + logical, intent(in), optional :: space |
1231 | + logical, intent(in), optional :: line_feed |
1232 | + character(len=*), intent(in), optional :: fmt |
1233 | + |
1234 | + call xml_AddPcdata_Ch(xf,trim(str(pcdata,fmt)),space,line_feed) |
1235 | + |
1236 | + end subroutine xml_AddPcdata_SP |
1237 | + |
1238 | + |
1239 | + subroutine xml_AddPcdata_DP(xf,pcdata,fmt,space,line_feed) |
1240 | + type(xmlf_t), intent(inout) :: xf |
1241 | + real(kind=dp), intent(in) :: pcdata |
1242 | + character(len=*), optional :: fmt |
1243 | + logical, intent(in), optional :: space |
1244 | + logical, intent(in), optional :: line_feed |
1245 | + |
1246 | + call xml_AddPcdata_Ch(xf,trim(str(pcdata,fmt)),space,line_feed) |
1247 | + |
1248 | + end subroutine xml_AddPcdata_DP |
1249 | + |
1250 | + |
1251 | + subroutine xml_AddPcdata_log(xf,pcdata,fmt,space,line_feed) |
1252 | + type(xmlf_t), intent(inout) :: xf |
1253 | + logical, intent(in) :: pcdata |
1254 | + character(len=*), intent(in), optional :: fmt |
1255 | + logical, intent(in), optional :: space |
1256 | + logical, intent(in), optional :: line_feed |
1257 | + |
1258 | + if (present(fmt)) then |
1259 | + call xml_AddPcdata_Ch(xf,trim(str(pcdata,fmt)),space,line_feed) |
1260 | + else |
1261 | + call xml_AddPcdata_Ch(xf,trim(str(pcdata)),space,line_feed) |
1262 | + endif |
1263 | + |
1264 | + end subroutine xml_AddPcdata_log |
1265 | + |
1266 | + |
1267 | + subroutine xml_AddPcdata_int(xf,pcdata,fmt,space,line_feed) |
1268 | + type(xmlf_t), intent(inout) :: xf |
1269 | + integer, intent(in) :: pcdata |
1270 | + character(len=*), intent(in), optional :: fmt |
1271 | + logical, intent(in), optional :: space |
1272 | + logical, intent(in), optional :: line_feed |
1273 | + |
1274 | + if (present(fmt)) then |
1275 | + call xml_AddPcdata_Ch(xf,trim(str(pcdata,fmt)),space,line_feed) |
1276 | + else |
1277 | + call xml_AddPcdata_Ch(xf,trim(str(pcdata)),space,line_feed) |
1278 | + endif |
1279 | + |
1280 | + end subroutine xml_AddPcdata_int |
1281 | + |
1282 | + |
1283 | + !------------------------------------------------------------------- |
1284 | + |
1285 | + subroutine xml_AddAttribute_SP(xf,name,value,fmt) |
1286 | + type(xmlf_t), intent(inout) :: xf |
1287 | + character(len=*), intent(in) :: name |
1288 | + real(kind=sp), intent(in) :: value |
1289 | + character(len=*), intent(in), optional :: fmt |
1290 | + |
1291 | + call xml_AddAttribute_Ch(xf,name,trim(str(value,fmt))) |
1292 | + |
1293 | + end subroutine xml_AddAttribute_SP |
1294 | + |
1295 | + subroutine xml_AddAttribute_DP(xf,name,value,fmt) |
1296 | + type(xmlf_t), intent(inout) :: xf |
1297 | + character(len=*), intent(in) :: name |
1298 | + real(kind=dp), intent(in) :: value |
1299 | + character(len=*), intent(in), optional :: fmt |
1300 | + |
1301 | + call xml_AddAttribute_Ch(xf,name,trim(str(value,fmt))) |
1302 | + |
1303 | + end subroutine xml_AddAttribute_DP |
1304 | + |
1305 | + subroutine xml_AddAttribute_log(xf,name,value,fmt) |
1306 | + type(xmlf_t), intent(inout) :: xf |
1307 | + character(len=*), intent(in) :: name |
1308 | + logical, intent(in) :: value |
1309 | + character(len=*), intent(in), optional :: fmt |
1310 | + |
1311 | + if (present(fmt)) then |
1312 | + call xml_AddAttribute_Ch(xf,name,trim(str(value,fmt))) |
1313 | + else |
1314 | + call xml_AddAttribute_Ch(xf,name,trim(str(value))) |
1315 | + endif |
1316 | + |
1317 | + end subroutine xml_AddAttribute_log |
1318 | + |
1319 | + subroutine xml_AddAttribute_int(xf,name,value,fmt) |
1320 | + type(xmlf_t), intent(inout) :: xf |
1321 | + character(len=*), intent(in) :: name |
1322 | + integer, intent(in) :: value |
1323 | + character(len=*), intent(in), optional :: fmt |
1324 | + |
1325 | + if (present(fmt)) then |
1326 | + call xml_AddAttribute_Ch(xf,name,trim(str(value,fmt))) |
1327 | + else |
1328 | + call xml_AddAttribute_Ch(xf,name,trim(str(value))) |
1329 | + endif |
1330 | + |
1331 | + end subroutine xml_AddAttribute_int |
1332 | + |
1333 | +end module m_wxml_overloads |
1334 | + |
1335 | |
1336 | === renamed file 'wxml/m_wxml_text.f90' => 'wxml/m_wxml_text.F90' |
1337 | --- wxml/m_wxml_text.f90 2014-09-04 14:11:50 +0000 |
1338 | +++ wxml/m_wxml_text.F90 2016-01-30 12:34:50 +0000 |
1339 | @@ -1,44 +1,68 @@ |
1340 | module m_wxml_text |
1341 | + |
1342 | +implicit none |
1343 | ! |
1344 | integer, private, parameter :: sp = selected_real_kind(6,30) |
1345 | integer, private, parameter :: dp = selected_real_kind(14,100) |
1346 | ! |
1347 | private |
1348 | - |
1349 | public :: str |
1350 | |
1351 | interface str |
1352 | - module procedure str_integer, str_real_dp, str_real_sp, & |
1353 | - str_logical |
1354 | + module procedure str_integer_fmt, str_integer, & |
1355 | + str_logical_fmt, str_logical, & |
1356 | + str_real_dp, str_real_sp |
1357 | end interface |
1358 | -private :: str_integer, str_real_dp, str_real_sp, str_logical |
1359 | |
1360 | CONTAINS |
1361 | |
1362 | - function str_integer(int,format) result(s) |
1363 | - integer, intent(in) :: int |
1364 | - character(len=*), intent(in), optional :: format |
1365 | + function str_integer_fmt(i,format) result(s) |
1366 | + integer, intent(in) :: i |
1367 | + character(len=*), intent(in) :: format |
1368 | character(len=100) :: s |
1369 | |
1370 | - if (present(format)) then |
1371 | - write(s,format) int |
1372 | - else |
1373 | - write(s,"(i25)") int |
1374 | - endif |
1375 | + write(s,format) i |
1376 | s = adjustl(s) |
1377 | + end function str_integer_fmt |
1378 | + |
1379 | + function str_integer(i) result(s) |
1380 | + ! This will work correctly (return an appropriately-sized |
1381 | + ! string) for integers i s.t. -99999999<=i<=999999999 |
1382 | + integer, intent(in) :: i |
1383 | +#ifndef WXML_INIT_FIX |
1384 | + character(len=int(merge(log10(real(max(abs(i),1)))+1, & |
1385 | + log10(real(max(abs(i),1)))+2, & |
1386 | + sign(1,i)>0))) :: s |
1387 | +#else |
1388 | +! Some compilers have trouble with the above |
1389 | + character(len=int(log10(real(max(abs(i),1)))+2)) :: s |
1390 | +#endif |
1391 | + character(len=4) :: form |
1392 | + |
1393 | + write(form,'(a,i1,a)') '(i',len(s),')' |
1394 | + write(s, form) i |
1395 | + |
1396 | end function str_integer |
1397 | |
1398 | - function str_logical(log,format) result(s) |
1399 | - logical, intent(in) :: log |
1400 | - character(len=*), intent(in), optional :: format |
1401 | + function str_logical_fmt(l,format) result(s) |
1402 | + logical, intent(in) :: l |
1403 | + character(len=*), intent(in) :: format |
1404 | character(len=100) :: s |
1405 | |
1406 | - if (present(format)) then |
1407 | - write(s,format) log |
1408 | - else |
1409 | - write(s,"(l1)") log |
1410 | - endif |
1411 | + write(s,format) l |
1412 | s = adjustl(s) |
1413 | + |
1414 | + end function str_logical_fmt |
1415 | + |
1416 | + function str_logical(l) result(s) |
1417 | + logical, intent(in) :: l |
1418 | + character(len=merge(4,5,l)) :: s |
1419 | + |
1420 | + if (l) then |
1421 | + s='true' |
1422 | + else |
1423 | + s='false' |
1424 | + endif |
1425 | end function str_logical |
1426 | |
1427 | function str_real_dp(x,format) result(s) |
1428 | @@ -47,10 +71,10 @@ |
1429 | character(len=100) :: s |
1430 | |
1431 | if (present(format)) then |
1432 | - write(s,format) x |
1433 | + write(s,format) x |
1434 | else |
1435 | if (abs(nint(x)-x) .lt. epsilon(x)) then |
1436 | - write(s,"(f20.0)") x |
1437 | + write(s,"(i0)") nint(x) |
1438 | else |
1439 | write(s,"(g22.12)") x |
1440 | endif |
1441 | @@ -67,7 +91,7 @@ |
1442 | write(s,format) x |
1443 | else |
1444 | if (abs(nint(x)-x) .lt. epsilon(x)) then |
1445 | - write(s,"(f20.0)") x |
1446 | + write(s,"(i0)") nint(x) |
1447 | else |
1448 | write(s,"(g22.12)") x |
1449 | endif |
1450 | |
1451 | === modified file 'wxml/makefile' |
1452 | --- wxml/makefile 2016-01-15 15:49:14 +0000 |
1453 | +++ wxml/makefile 2016-01-30 12:34:50 +0000 |
1454 | @@ -1,6 +1,8 @@ |
1455 | # |
1456 | -OBJFILES= m_wxml_buffer.o m_wxml_dictionary.o m_wxml_elstack.o \ |
1457 | - m_wxml_text.o m_wxml_core.o xmlf90_wxml.o |
1458 | +OBJFILES= m_wxml_buffer.o m_wxml_array_str.o m_wxml_dictionary.o\ |
1459 | + m_wxml_elstack.o \ |
1460 | + m_wxml_text.o m_wxml_escape.o m_wxml_core.o \ |
1461 | + m_wxml_overloads.o xmlf90_wxml.o m_wxml_error.o |
1462 | MODFILES=$(OBJFILES:.o=) |
1463 | |
1464 | #------------------------------ |
1465 | @@ -10,4 +12,12 @@ |
1466 | |
1467 | clean: |
1468 | rm -f *.o *.$(MOD_EXT) |
1469 | +# DO NOT DELETE THIS LINE - used by make depend |
1470 | +xmlf90_wxml.o: m_wxml_core.o m_wxml_overloads.o m_wxml_text.o |
1471 | +m_wxml_buffer.o: m_wxml_error.o m_wxml_escape.o |
1472 | +m_wxml_core.o: m_wxml_buffer.o m_wxml_dictionary.o m_wxml_elstack.o |
1473 | +m_wxml_core.o: m_wxml_escape.o m_wxml_array_str.o |
1474 | +m_wxml_dictionary.o: m_wxml_array_str.o m_wxml_escape.o |
1475 | +m_wxml_elstack.o: m_wxml_error.o |
1476 | +m_wxml_overloads.o: m_wxml_core.o m_wxml_text.o |
1477 | |
1478 | |
1479 | === modified file 'wxml/xmlf90_wxml.f90' |
1480 | --- wxml/xmlf90_wxml.f90 2016-01-15 15:49:14 +0000 |
1481 | +++ wxml/xmlf90_wxml.f90 2016-01-30 12:34:50 +0000 |
1482 | @@ -1,10 +1,8 @@ |
1483 | module xmlf90_wxml |
1484 | |
1485 | -!use m_wxml_buffer |
1486 | -!use m_wxml_dictionary |
1487 | -!use m_wxml_elstack |
1488 | use m_wxml_text |
1489 | use m_wxml_core |
1490 | +use m_wxml_overloads |
1491 | |
1492 | public |
1493 |
The wxml test shows that there has been a regression: "real" attribute values are not trimmed.