diff --git a/vlib/strconv/format.v b/vlib/strconv/format.v index 4e70bbaeb9..1ccaf25db1 100644 --- a/vlib/strconv/format.v +++ b/vlib/strconv/format.v @@ -14,23 +14,23 @@ import strconv.ftoa import strings enum Char_parse_state { - start, - norm_char, - field_char, - pad_ch, - len_set_start, - len_set_in, + start + norm_char + field_char + pad_ch + len_set_start + len_set_in - check_type, - check_float, - check_float_in, + check_type + check_float + check_float_in reset_params } enum Align_text { - right = 0, - left, + right = 0 + left center } @@ -127,6 +127,7 @@ pub fn f64_to_str_lnd(f f64, dec_digit int) string { } // allocate exp+32 chars for the return string + //mut res := []byte{len:exp+32,init:`0`} mut res := [`0`].repeat(exp+32) // TODO: Slow!! is there other possibilities to allocate this? mut r_i := 0 // result string buffer index @@ -205,7 +206,7 @@ struct BF_param { pad_ch byte = ` ` // padding char len0 int = -1 // default len for whole the number or string len1 int = 6 // number of decimal digits, if needed - positive bool = true // mandatory: the sign of the number passed + positive bool = true // mandatory: the sign of the number passed sign_flag bool = false // flag for print sign as prefix in padding allign Align_text = .right // alignment of the string rm_tail_zero bool = false // remove the tail zeros from floats @@ -219,13 +220,13 @@ pub fn format_str(s string, p BF_param) string { mut res := strings.new_builder(s.len + dif) if p.allign == .right { for i1 :=0; i1 < dif; i1++ { - res.write_b(p.pad_ch) + res.write_b(p.pad_ch) } } res.write(s) if p.allign == .left { for i1 :=0; i1 < dif; i1++ { - res.write_b(p.pad_ch) + res.write_b(p.pad_ch) } } return res.str() @@ -258,19 +259,17 @@ pub fn format_dec(d u64, p BF_param) string { s = "-" + d.str() } } - dif := p.len0 - s.len + sign_len_diff if p.allign == .right { for i1 :=0; i1 < dif; i1++ { - res.write_b(p.pad_ch) + res.write_b(p.pad_ch) } } - res.write(s) if p.allign == .left { for i1 :=0; i1 < dif; i1++ { - res.write_b(p.pad_ch) + res.write_b(p.pad_ch) } } return res.str() @@ -279,6 +278,12 @@ pub fn format_dec(d u64, p BF_param) string { pub fn format_fl(f f64, p BF_param) string { mut s := "" mut fs := f64_to_str_lnd(if f >= 0.0 {f} else {-f}, p.len1) + + // error!! + if fs[0] == `[` { + return fs + } + if p.rm_tail_zero { fs = remove_tail_zeros(fs) } @@ -312,14 +317,13 @@ pub fn format_fl(f f64, p BF_param) string { if p.allign == .right { for i1 :=0; i1 < dif; i1++ { - res.write_b(p.pad_ch) + res.write_b(p.pad_ch) } } - res.write(s) if p.allign == .left { for i1 :=0; i1 < dif; i1++ { - res.write_b(p.pad_ch) + res.write_b(p.pad_ch) } } @@ -361,13 +365,13 @@ pub fn format_es(f f64, p BF_param) string { dif := p.len0 - s.len + sign_len_diff if p.allign == .right { for i1 :=0; i1 < dif; i1++ { - res.write_b(p.pad_ch) + res.write_b(p.pad_ch) } } res.write(s) if p.allign == .left { for i1 :=0; i1 < dif; i1++ { - res.write_b(p.pad_ch) + res.write_b(p.pad_ch) } } return res.str() @@ -411,7 +415,6 @@ pub fn remove_tail_zeros(s string) string { if tmp.str[tmp.len-1] == `.` { return tmp[..tmp.len-1] } - return tmp } @@ -442,7 +445,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ mut ch1 := `0` // +1 char if present else `0` mut ch2 := `0` // +2 char if present else `0` - mut status := Char_parse_state.norm_char for i < str.len { if status == .reset_params { @@ -459,13 +461,11 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ } ch := str[i] - if ch != `%` && status == .norm_char { res.write_b(ch) i++ continue - } - + } if ch == `%` && status == .norm_char { status = .field_char i++ @@ -500,7 +500,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ fc_ch2 = str[i+2] } } - if ch == `+` { sign = true i++ @@ -531,8 +530,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ mut s := *(&string(pt[p_index])) s = s[..len] p_index++ - res.write(s) - + res.write(s) status = .reset_params i += 3 continue @@ -607,8 +605,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ i++ continue } - } - + } else if ch == `h` { if ch1 == `0` { ch1 = `h` @@ -668,7 +665,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ } res.write(format_dec(d1,{positive: positive, pad_ch: pad_ch, len0: len0, sign_flag: sign, allign: allign})) - status = .reset_params p_index++ i++ @@ -812,9 +808,8 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ // string else if ch == `s` { s1 := *(&string(pt[p_index])) - pad_ch = `0` + pad_ch = ` ` res.write(format_str(s1, {pad_ch: pad_ch, len0: len0, allign: allign})) - status = .reset_params p_index++ i++ @@ -825,7 +820,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ status = .reset_params p_index++ i++ - } return res.str() diff --git a/vlib/strconv/format_test.v b/vlib/strconv/format_test.v index 367c190162..bf60bedd22 100644 --- a/vlib/strconv/format_test.v +++ b/vlib/strconv/format_test.v @@ -2,107 +2,110 @@ import os import strconv fn test_format(){ - - if os.getenv('FORCE_FORMAT_TEST') != '1' { - $if !macos { - eprintln('This test is done only on macos for now.') - eprintln('LibC sprintfs implementations on other platforms have too much variation in edge cases.') - eprintln('If you still want to do it, use `FORCE_FORMAT_TEST=1 ./v -cg vlib/strconv/format_test.v`') - exit(0) - } - } - - mut buf := [1024]byte mut temp_s := "" + mut tmp_str:= "" a0 := u32(10) b0 := 200 c0 := byte(12) s0 := "ciAo" ch0 := `B` - f0 := 0.312345 f1 := 200000.0 f2 := -1234.300e6 f3 := 1234.300e-6 - sc0 := "ciao: [%-08u] %d %hhd [%08s]\nr2: [%08X] [%p] [%-20.4f] [%-20.4f] [%c]\n" - temp_s = strconv.v_sprintf(sc0 ,a0 ,b0 ,c0 ,s0 ,b0 ,&b0 ,f0, f1, ch0) - C.sprintf(buf, sc0.str,a0 ,b0 ,c0 ,s0.str ,b0 ,&b0 ,f0, f1, ch0) - - $if debug { - eprintln('C sprintf:') - eprintln( tos2(buf) ) - eprintln( tos2(buf).bytes().hex() ) - eprintln('V sprintf:') - eprintln( temp_s ) - eprintln( temp_s.bytes().hex() ) - } - - assert tos2(buf) == temp_s + sc0 := "ciao: [%-08u] %d %hhd [%8s] [%08X] [%-20.4f] [%-20.4f] [%c]" + temp_s = strconv.v_sprintf(sc0 ,a0 ,b0 ,c0 ,s0, b0 ,f0, f1, ch0) + tmp_str = "ciao: [10 ] 200 12 [ ciAo] [000000C8] [0.3123 ] [200000.0000 ] [B]" + //C.printf(sc0.str,a0 ,b0 ,c0 ,s0.str ,b0 ,f0, f1, ch0) + //println("\n$temp_s") + assert tmp_str == temp_s a := byte(12) b := i16(13) c := 14 d := i64(15) - sc1 := "==>%hhd %hd %d %ld\n" + sc1 := "==>%hhd %hd %d %ld" temp_s = strconv.v_sprintf(sc1, a ,b ,c, d) - C.sprintf(buf, sc1.str, a ,b ,c, d) - //println("$temp_s${tos2(buf)}") - assert tos2(buf) == temp_s + tmp_str = "==>12 13 14 15" + //C.printf(sc1.str, a ,b ,c, d) + //println("\n$temp_s") + assert tmp_str == temp_s a1 := byte(0xff) b1 := i16(0xffff) c1 := u32(0xffff_ffff) d1 := u64(-1) - sc2 := "%hhu %hu %u %lu\n" + sc2 := "%hhu %hu %u %lu" temp_s = strconv.v_sprintf(sc2, a1 ,b1 ,c1, d1) - C.sprintf(buf, sc2.str, a1 ,b1 ,c1, d1) - //println("$temp_s${tos2(buf)}") - assert tos2(buf) == temp_s + tmp_str = "255 65535 4294967295 18446744073709551615" + //C.printf(sc2.str, a1 ,b1 ,c1, d1) + //println("\n$temp_s") + assert tmp_str == temp_s - - sc3 := "%hhx %hx %x %lx\n" + sc3 := "%hhx %hx %x %lx" temp_s = strconv.v_sprintf(sc3, a1 ,b1 ,c1, d1) - C.sprintf(buf, sc3.str, a1 ,b1 ,c1, d1) - //println("$temp_s${tos2(buf)}") - assert tos2(buf) == temp_s - + tmp_str = "ff ffff ffffffff ffffffffffffffff" + //C.printf(sc3.str, a1 ,b1 ,c1, d1) + //println("\n$temp_s") + assert tmp_str == temp_s - sc4 := "[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]\n" + sc4 := "[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]" temp_s = strconv.v_sprintf(sc4, f0, f1, f1, f1, f2, f3) - C.sprintf(buf, sc4.str, f0, f1, f1, f1, f2, f3) - //println("$temp_s${tos2(buf)}") - assert tos2(buf) == temp_s - - sc5 := "[%.3f] [%0.3f] [%0.3F] [%0.3f] [%0.3F]\n" - temp_s = strconv.v_sprintf(sc5, f0, f1, f1, f2, f3, f3) - C.sprintf(buf, sc5.str, f0, f1, f1, f2, f3, f3) - //println("$temp_s${tos2(buf)}") - assert tos2(buf) == temp_s + tmp_str = "[3.123e-01 ] [ 2.000e+05] [2.000e+05 ] [2.000E+05 ] [-1.234e+09 ] [1.234e-03 ]" + //C.printf(sc4.str, f0, f1, f1, f1, f2, f3) + //println("\n$temp_s") + assert tmp_str == temp_s + sc5 := "[%.3f] [%0.3f] [%0.3F] [%0.3f] [%0.3F]" + temp_s = strconv.v_sprintf(sc5, f0, f1, f1, f2, f3, f3) + tmp_str = "[0.312] [200000.000] [200000.000] [-1234300000.000] [0.001]" + //C.printf(sc5.str, f0, f1, f1, f2, f3, f3) + //println("\n$temp_s") + assert tmp_str == temp_s + ml := 3 - sc6 := "%.*s [%05hhX]\n" + sc6 := "%.*s [%05hhX]" temp_s = strconv.v_sprintf(sc6, ml, s0 , a) - C.sprintf(buf, sc6.str, ml, s0.str, a) - //println("$temp_s${tos2(buf)}") - assert tos2(buf) == temp_s + tmp_str = "ciA [0000C]" + //C.printf(sc6.str, ml, s0.str, a) + //println("\n$temp_s") + assert tmp_str == temp_s a2 := 125 - sc7 := "[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]\n" + sc7 := "[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]" temp_s = strconv.v_sprintf(sc7, a2, a2, a2, a2, a2, a2) - C.sprintf(buf, sc7.str, a2, a2, a2, a2, a2, a2) - //println("$temp_s${tos2(buf)}") - assert tos2(buf) == temp_s + tmp_str = "[ 7d] [ 7D] [7d ] [7D ] [00000007d] [00000007D]" + //C.printf(sc7.str, a2, a2, a2, a2, a2, a2) + //println("\n$temp_s") + assert tmp_str == temp_s + + g_test := [ + "[ -1e-07][ -1E-07]|", + "[ -1e-06][ -1E-06]|", + "[ -1e-05][ -1E-05]|", + "[ -0.0001][ -0.0001]|", + "[ -0.001][ -0.001]|", + "[ -0.01][ -0.01]|", + "[ -0.1][ -0.1]|", + "[ -1][ -1]|", + "[ -10][ -10]|", + "[ -100][ -100]|", + "[ -1000][ -1000]|", + "[ -10000][ -10000]|" + ] mut ft := -1e-7 mut x := 0 + mut cnt:= 0 sc8 := "[%20g][%20G]|" for x < 12 { temp_s = strconv.v_sprintf(sc8, ft, ft) - C.sprintf(buf,sc8.str, ft, ft) - //println("$temp_s ${tos2(buf)}") - assert tos2(buf) == temp_s + //C.printf(sc8.str, ft, ft) + //println("\n$temp_s") + assert temp_s == g_test[cnt] ft = ft * 10.0 x++ + cnt++ } }