@@ -116,10 +116,10 @@ module json_module
116116 ! default integer kind [4 bytes]
117117 integer ,parameter :: IK = int32
118118
119- ! default character kind [1 byte]
119+ ! default character kind [1 byte]
120120 integer ,parameter :: CK = character_kinds(1 )
121121
122- ! default logical kind [4 bytes]
122+ ! default logical kind [4 bytes]
123123 ! The statement here is to ensure a valid kind
124124 ! if the compiler doesn't have a logical_kinds(3)
125125 integer ,parameter :: LK = logical_kinds(min (3 ,size (logical_kinds)))
@@ -149,9 +149,19 @@ module json_module
149149
150150 integer (IK),parameter :: spaces_per_tab = 2 ! for indenting (Note: jsonlint.com uses 4 spaces)
151151
152- integer (IK),parameter :: max_numeric_str_len = 32
153- character (kind= CK,len=* ),parameter :: real_fmt = ' (E30.16E3)' ! format for real numbers
154- character (kind= CK,len=* ),parameter :: int_fmt = ' (I10)' ! format for integers
152+ ! find out the precision of the floating point number system, in io use 4Xprecision
153+ integer (IK),parameter :: rp_safety_factor = 1
154+ integer (IK),parameter :: rp_addl_safety = 1
155+ integer (IK),parameter :: real_precision = rp_safety_factor* precision (1.0_RK ) + rp_addl_safety
156+ ! Get the number of possible digits in the exponent when using decimal number system
157+ integer (IK),parameter :: real_exponent_digits = ceiling ( log10 ( &
158+ real (max (maxexponent (1.0_RK ),abs (minexponent (1.0_RK ))),kind= RK) &
159+ ) )
160+ ! 4*precision to prevent rounding errors
161+ ! 6 = sign + leading 0 + decimal + 'E' + exponent sign + 1 extra
162+ integer (IK),parameter :: max_numeric_str_len = real_precision + real_exponent_digits + 6
163+ ! real format set by library initialization
164+ character (kind= CK,len=* ),parameter :: int_fmt = ' (I0)' ! minimum width format for integers
155165 character (kind= CK,len=* ),parameter :: star = ' *' ! for invalid numbers
156166
157167 ! *********************************************************
@@ -532,6 +542,7 @@ end subroutine array_callback_func
532542 ! Note: the following global variables make this module non thread safe.
533543 !
534544
545+ character (kind= CK,len= :),allocatable :: real_fmt
535546 ! exception handling [private variables]
536547 logical (LK) :: is_verbose = .false. ! if true, all exceptions are immediately printed to console
537548 logical (LK) :: exception_thrown = .false. ! the error flag
@@ -1234,20 +1245,29 @@ end subroutine json_file_get_string_vec
12341245! AUTHOR
12351246! Jacob Williams : 12/4/2013
12361247!
1248+ ! MODIFIED
1249+ ! Izaak Beekman : 02/24/2015
1250+ !
12371251! SOURCE
12381252
12391253 subroutine json_initialize (verbose )
12401254
12411255 implicit none
12421256
12431257 logical (LK),intent (in ),optional :: verbose ! mainly useful for debugging (default is false)
1244-
1258+ character (kind = CK,len = 10 ) :: w,d,e
12451259 ! optional input (if not present, value remains unchanged):
12461260 if (present (verbose)) is_verbose = verbose
12471261
12481262 ! clear any errors from previous runs:
12491263 call json_clear_exceptions()
12501264
1265+ ! set the output/input format for reals:
1266+ write (w,' (I0)' ) max_numeric_str_len
1267+ write (d,' (I0)' ) real_precision
1268+ write (e,' (I0)' ) real_exponent_digits
1269+ real_fmt = ' (e' // trim (w) // ' .' // trim (d) // ' e' // trim (e) // ' )'
1270+
12511271 ! Just in case, clear these global variables also:
12521272 pushed_index = 0
12531273 pushed_char = ' '
@@ -1553,7 +1573,7 @@ subroutine json_value_remove(me,destroy)
15531573
15541574 if (associated (me% parent)) then
15551575
1556- parent = > me% parent
1576+ parent = > me% parent
15571577
15581578 if (associated (me% next)) then
15591579
@@ -1562,7 +1582,7 @@ subroutine json_value_remove(me,destroy)
15621582 next = > me% next
15631583 nullify(me% next)
15641584
1565- if (associated (me% previous)) then
1585+ if (associated (me% previous)) then
15661586 ! there are earlier items in the list
15671587 previous = > me% previous
15681588 previous% next = > next
@@ -2811,7 +2831,7 @@ recursive subroutine json_value_print(this,iunit,str,indent,need_comma,colon,is_
28112831
28122832 end do
28132833
2814- ! indent the closing array character:
2834+ ! indent the closing array character:
28152835 call write_it( repeat (space, max (0 ,spaces- spaces_per_tab))// end_array,&
28162836 comma= print_comma )
28172837 nullify(element)
@@ -3696,10 +3716,10 @@ subroutine json_get_string(this, path, value, found)
36963716
36973717 s = pre// c// post
36983718
3699- n = n-1 ! backslash character has been
3719+ n = n-1 ! backslash character has been
37003720 ! removed from the string
37013721
3702- case (' u' ) ! expecting 4 hexadecimal digits after
3722+ case (' u' ) ! expecting 4 hexadecimal digits after
37033723 ! the escape character [\uXXXX]
37043724
37053725 ! for now, we are just printing them as is
@@ -3987,7 +4007,7 @@ subroutine json_parse(file, p, unit, str)
39874007 return
39884008 end if
39894009
3990- iunit = unit
4010+ iunit = unit
39914011
39924012 ! check to see if the file is already open
39934013 ! if it is, then use it, otherwise open the file with the name given.
@@ -4614,6 +4634,9 @@ end subroutine to_double
46144634! AUTHOR
46154635! Jacob Williams
46164636!
4637+ ! MODIFIED
4638+ ! Izaak Beekman : 02/24/2015
4639+ !
46174640! SOURCE
46184641
46194642 subroutine to_string (me ,val ,name )
@@ -5233,7 +5256,7 @@ recursive function pop_char(unit, str, eof, skip_ws) result(popped)
52335256
52345257 end if
52355258
5236- if (iachar (c) <= 31 ) then ! JW : fixed so it will read spaces
5259+ if (iachar (c) <= 31 ) then ! JW : fixed so it will read spaces
52375260 ! in the string (was 32)
52385261
52395262 ! non printing ascii characters
@@ -5348,12 +5371,62 @@ subroutine real_to_string(rval,str)
53485371 real (RK),intent (in ) :: rval
53495372 character (kind= CK,len=* ),intent (out ) :: str
53505373
5351- integer (IK) :: istat
5374+ character (kind= CK,len= len (str)) :: significand, expnt
5375+ character (kind= CK,len= 2 ) :: separator
5376+ integer (IK) :: istat, exp_start, decimal_pos, sig_trim, exp_trim, i
53525377
53535378 write (str,fmt= real_fmt,iostat= istat) rval
53545379
53555380 if (istat== 0 ) then
53565381 str = adjustl (str)
5382+ exp_start = scan (str,CK_' eEdD' )
5383+ if (exp_start == 0 ) exp_start = scan (str,CK_' -+' ,back= .true. )
5384+ decimal_pos = scan (str,CK_' .' )
5385+ if (exp_start /= 0 ) separator = str(exp_start:exp_start)
5386+ if (exp_start > 0 .and. exp_start < decimal_pos) then ! signed, exponent-less float
5387+ significand = str
5388+ sig_trim = len (trim (significand))
5389+ do i = len (trim (significand)),decimal_pos+2 ,- 1 ! look from right to left at 0s
5390+ ! but save one after the decimal place
5391+ if (significand(i:i) == CK_' 0' ) then
5392+ sig_trim = i-1
5393+ else
5394+ exit
5395+ end if
5396+ end do
5397+ str = trim (significand(1 :sig_trim))
5398+ else if (exp_start > decimal_pos) then ! float has exponent
5399+ significand = str(1 :exp_start-1 )
5400+ sig_trim = len (trim (significand))
5401+ do i = len (trim (significand)),decimal_pos+2 ,- 1 ! look from right to left at 0s
5402+ if (significand(i:i) == CK_' 0' ) then
5403+ sig_trim = i-1
5404+ else
5405+ exit
5406+ end if
5407+ end do
5408+ expnt = adjustl (str(exp_start+1 :))
5409+ if (expnt(1 :1 ) == CK_' +' .or. expnt(1 :1 ) == CK_' -' ) then
5410+ separator = trim (adjustl (separator))// expnt(1 :1 )
5411+ exp_start = exp_start + 1
5412+ expnt = adjustl (str(exp_start+1 :))
5413+ end if
5414+ exp_trim = 1
5415+ do i = 1 ,(len (trim (expnt))- 1 ) ! look at exponent leading zeros saving last
5416+ if (expnt(i:i) == CK_' 0' ) then
5417+ exp_trim = i+1
5418+ else
5419+ exit
5420+ end if
5421+ end do
5422+ str = trim (adjustl (significand(1 :sig_trim)))// &
5423+ trim (adjustl (separator))// &
5424+ trim (adjustl (expnt(exp_trim:)))
5425+
5426+ ! else ! mal-formed real, BUT this code should be unreachable
5427+
5428+ end if
5429+
53575430 else
53585431 str = repeat (star,len (str))
53595432 end if
0 commit comments