@@ -80,10 +80,19 @@ function Format(f::AbstractString)
80
80
len = length (bytes)
81
81
pos = 1
82
82
b = 0x00
83
- while true
83
+ while pos <= len
84
84
b = bytes[pos]
85
85
pos += 1
86
- (pos > len || (b == UInt8 (' %' ) && pos <= len && bytes[pos] != UInt8 (' %' ))) && break
86
+ if b == UInt8 (' %' )
87
+ pos > len && throw (ArgumentError (" invalid format string: '$f '" ))
88
+ if bytes[pos] == UInt8 (' %' )
89
+ # escaped '%'
90
+ b = bytes[pos]
91
+ pos += 1
92
+ else
93
+ break
94
+ end
95
+ end
87
96
end
88
97
strs = [1 : pos - 1 - (b == UInt8 (' %' ))]
89
98
fmts = []
@@ -645,9 +654,16 @@ const UNROLL_UPTO = 16
645
654
# if you have your own buffer + pos, write formatted args directly to it
646
655
@inline function format (buf:: Vector{UInt8} , pos:: Integer , f:: Format , args... )
647
656
# write out first substring
657
+ escapechar = false
648
658
for i in f. substringranges[1 ]
649
- buf[pos] = f. str[i]
650
- pos += 1
659
+ b = f. str[i]
660
+ if ! escapechar
661
+ buf[pos] = b
662
+ pos += 1
663
+ escapechar = b === UInt8 (' %' )
664
+ else
665
+ escapechar = false
666
+ end
651
667
end
652
668
# for each format, write out arg and next substring
653
669
# unroll up to 16 formats
@@ -656,17 +672,29 @@ const UNROLL_UPTO = 16
656
672
if N >= i
657
673
pos = fmt (buf, pos, args[i], f. formats[i])
658
674
for j in f. substringranges[i + 1 ]
659
- buf[pos] = f. str[j]
660
- pos += 1
675
+ b = f. str[j]
676
+ if ! escapechar
677
+ buf[pos] = b
678
+ pos += 1
679
+ escapechar = b === UInt8 (' %' )
680
+ else
681
+ escapechar = false
682
+ end
661
683
end
662
684
end
663
685
end
664
686
if N > 16
665
687
for i = 17 : length (f. formats)
666
688
pos = fmt (buf, pos, args[i], f. formats[i])
667
689
for j in f. substringranges[i + 1 ]
668
- buf[pos] = f. str[j]
669
- pos += 1
690
+ b = f. str[j]
691
+ if ! escapechar
692
+ buf[pos] = b
693
+ pos += 1
694
+ escapechar = b === UInt8 (' %' )
695
+ else
696
+ escapechar = false
697
+ end
670
698
end
671
699
end
672
700
end
0 commit comments