github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/text/message/format.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package message 6 7 import ( 8 "bytes" 9 "strconv" 10 "unicode/utf8" 11 12 "golang.org/x/text/internal/format" 13 ) 14 15 const ( 16 ldigits = "0123456789abcdefx" 17 udigits = "0123456789ABCDEFX" 18 ) 19 20 const ( 21 signed = true 22 unsigned = false 23 ) 24 25 // A formatInfo is the raw formatter used by Printf etc. 26 // It prints into a buffer that must be set up separately. 27 type formatInfo struct { 28 buf *bytes.Buffer 29 30 format.Parser 31 32 // intbuf is large enough to store %b of an int64 with a sign and 33 // avoids padding at the end of the struct on 32 bit architectures. 34 intbuf [68]byte 35 } 36 37 func (f *formatInfo) init(buf *bytes.Buffer) { 38 f.ClearFlags() 39 f.buf = buf 40 } 41 42 // writePadding generates n bytes of padding. 43 func (f *formatInfo) writePadding(n int) { 44 if n <= 0 { // No padding bytes needed. 45 return 46 } 47 f.buf.Grow(n) 48 // Decide which byte the padding should be filled with. 49 padByte := byte(' ') 50 if f.Zero { 51 padByte = byte('0') 52 } 53 // Fill padding with padByte. 54 for i := 0; i < n; i++ { 55 f.buf.WriteByte(padByte) // TODO: make more efficient. 56 } 57 } 58 59 // pad appends b to f.buf, padded on left (!f.minus) or right (f.minus). 60 func (f *formatInfo) pad(b []byte) { 61 if !f.WidthPresent || f.Width == 0 { 62 f.buf.Write(b) 63 return 64 } 65 width := f.Width - utf8.RuneCount(b) 66 if !f.Minus { 67 // left padding 68 f.writePadding(width) 69 f.buf.Write(b) 70 } else { 71 // right padding 72 f.buf.Write(b) 73 f.writePadding(width) 74 } 75 } 76 77 // padString appends s to f.buf, padded on left (!f.minus) or right (f.minus). 78 func (f *formatInfo) padString(s string) { 79 if !f.WidthPresent || f.Width == 0 { 80 f.buf.WriteString(s) 81 return 82 } 83 width := f.Width - utf8.RuneCountInString(s) 84 if !f.Minus { 85 // left padding 86 f.writePadding(width) 87 f.buf.WriteString(s) 88 } else { 89 // right padding 90 f.buf.WriteString(s) 91 f.writePadding(width) 92 } 93 } 94 95 // fmt_boolean formats a boolean. 96 func (f *formatInfo) fmt_boolean(v bool) { 97 if v { 98 f.padString("true") 99 } else { 100 f.padString("false") 101 } 102 } 103 104 // fmt_unicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'". 105 func (f *formatInfo) fmt_unicode(u uint64) { 106 buf := f.intbuf[0:] 107 108 // With default precision set the maximum needed buf length is 18 109 // for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits 110 // into the already allocated intbuf with a capacity of 68 bytes. 111 prec := 4 112 if f.PrecPresent && f.Prec > 4 { 113 prec = f.Prec 114 // Compute space needed for "U+" , number, " '", character, "'". 115 width := 2 + prec + 2 + utf8.UTFMax + 1 116 if width > len(buf) { 117 buf = make([]byte, width) 118 } 119 } 120 121 // Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left. 122 i := len(buf) 123 124 // For %#U we want to add a space and a quoted character at the end of the buffer. 125 if f.Sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) { 126 i-- 127 buf[i] = '\'' 128 i -= utf8.RuneLen(rune(u)) 129 utf8.EncodeRune(buf[i:], rune(u)) 130 i-- 131 buf[i] = '\'' 132 i-- 133 buf[i] = ' ' 134 } 135 // Format the Unicode code point u as a hexadecimal number. 136 for u >= 16 { 137 i-- 138 buf[i] = udigits[u&0xF] 139 prec-- 140 u >>= 4 141 } 142 i-- 143 buf[i] = udigits[u] 144 prec-- 145 // Add zeros in front of the number until requested precision is reached. 146 for prec > 0 { 147 i-- 148 buf[i] = '0' 149 prec-- 150 } 151 // Add a leading "U+". 152 i-- 153 buf[i] = '+' 154 i-- 155 buf[i] = 'U' 156 157 oldZero := f.Zero 158 f.Zero = false 159 f.pad(buf[i:]) 160 f.Zero = oldZero 161 } 162 163 // fmt_integer formats signed and unsigned integers. 164 func (f *formatInfo) fmt_integer(u uint64, base int, isSigned bool, digits string) { 165 negative := isSigned && int64(u) < 0 166 if negative { 167 u = -u 168 } 169 170 buf := f.intbuf[0:] 171 // The already allocated f.intbuf with a capacity of 68 bytes 172 // is large enough for integer formatting when no precision or width is set. 173 if f.WidthPresent || f.PrecPresent { 174 // Account 3 extra bytes for possible addition of a sign and "0x". 175 width := 3 + f.Width + f.Prec // wid and prec are always positive. 176 if width > len(buf) { 177 // We're going to need a bigger boat. 178 buf = make([]byte, width) 179 } 180 } 181 182 // Two ways to ask for extra leading zero digits: %.3d or %03d. 183 // If both are specified the f.zero flag is ignored and 184 // padding with spaces is used instead. 185 prec := 0 186 if f.PrecPresent { 187 prec = f.Prec 188 // Precision of 0 and value of 0 means "print nothing" but padding. 189 if prec == 0 && u == 0 { 190 oldZero := f.Zero 191 f.Zero = false 192 f.writePadding(f.Width) 193 f.Zero = oldZero 194 return 195 } 196 } else if f.Zero && f.WidthPresent { 197 prec = f.Width 198 if negative || f.Plus || f.Space { 199 prec-- // leave room for sign 200 } 201 } 202 203 // Because printing is easier right-to-left: format u into buf, ending at buf[i]. 204 // We could make things marginally faster by splitting the 32-bit case out 205 // into a separate block but it's not worth the duplication, so u has 64 bits. 206 i := len(buf) 207 // Use constants for the division and modulo for more efficient code. 208 // Switch cases ordered by popularity. 209 switch base { 210 case 10: 211 for u >= 10 { 212 i-- 213 next := u / 10 214 buf[i] = byte('0' + u - next*10) 215 u = next 216 } 217 case 16: 218 for u >= 16 { 219 i-- 220 buf[i] = digits[u&0xF] 221 u >>= 4 222 } 223 case 8: 224 for u >= 8 { 225 i-- 226 buf[i] = byte('0' + u&7) 227 u >>= 3 228 } 229 case 2: 230 for u >= 2 { 231 i-- 232 buf[i] = byte('0' + u&1) 233 u >>= 1 234 } 235 default: 236 panic("fmt: unknown base; can't happen") 237 } 238 i-- 239 buf[i] = digits[u] 240 for i > 0 && prec > len(buf)-i { 241 i-- 242 buf[i] = '0' 243 } 244 245 // Various prefixes: 0x, -, etc. 246 if f.Sharp { 247 switch base { 248 case 8: 249 if buf[i] != '0' { 250 i-- 251 buf[i] = '0' 252 } 253 case 16: 254 // Add a leading 0x or 0X. 255 i-- 256 buf[i] = digits[16] 257 i-- 258 buf[i] = '0' 259 } 260 } 261 262 if negative { 263 i-- 264 buf[i] = '-' 265 } else if f.Plus { 266 i-- 267 buf[i] = '+' 268 } else if f.Space { 269 i-- 270 buf[i] = ' ' 271 } 272 273 // Left padding with zeros has already been handled like precision earlier 274 // or the f.zero flag is ignored due to an explicitly set precision. 275 oldZero := f.Zero 276 f.Zero = false 277 f.pad(buf[i:]) 278 f.Zero = oldZero 279 } 280 281 // truncate truncates the string to the specified precision, if present. 282 func (f *formatInfo) truncate(s string) string { 283 if f.PrecPresent { 284 n := f.Prec 285 for i := range s { 286 n-- 287 if n < 0 { 288 return s[:i] 289 } 290 } 291 } 292 return s 293 } 294 295 // fmt_s formats a string. 296 func (f *formatInfo) fmt_s(s string) { 297 s = f.truncate(s) 298 f.padString(s) 299 } 300 301 // fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes. 302 func (f *formatInfo) fmt_sbx(s string, b []byte, digits string) { 303 length := len(b) 304 if b == nil { 305 // No byte slice present. Assume string s should be encoded. 306 length = len(s) 307 } 308 // Set length to not process more bytes than the precision demands. 309 if f.PrecPresent && f.Prec < length { 310 length = f.Prec 311 } 312 // Compute width of the encoding taking into account the f.sharp and f.space flag. 313 width := 2 * length 314 if width > 0 { 315 if f.Space { 316 // Each element encoded by two hexadecimals will get a leading 0x or 0X. 317 if f.Sharp { 318 width *= 2 319 } 320 // Elements will be separated by a space. 321 width += length - 1 322 } else if f.Sharp { 323 // Only a leading 0x or 0X will be added for the whole string. 324 width += 2 325 } 326 } else { // The byte slice or string that should be encoded is empty. 327 if f.WidthPresent { 328 f.writePadding(f.Width) 329 } 330 return 331 } 332 // Handle padding to the left. 333 if f.WidthPresent && f.Width > width && !f.Minus { 334 f.writePadding(f.Width - width) 335 } 336 // Write the encoding directly into the output buffer. 337 buf := f.buf 338 if f.Sharp { 339 // Add leading 0x or 0X. 340 buf.WriteByte('0') 341 buf.WriteByte(digits[16]) 342 } 343 var c byte 344 for i := 0; i < length; i++ { 345 if f.Space && i > 0 { 346 // Separate elements with a space. 347 buf.WriteByte(' ') 348 if f.Sharp { 349 // Add leading 0x or 0X for each element. 350 buf.WriteByte('0') 351 buf.WriteByte(digits[16]) 352 } 353 } 354 if b != nil { 355 c = b[i] // Take a byte from the input byte slice. 356 } else { 357 c = s[i] // Take a byte from the input string. 358 } 359 // Encode each byte as two hexadecimal digits. 360 buf.WriteByte(digits[c>>4]) 361 buf.WriteByte(digits[c&0xF]) 362 } 363 // Handle padding to the right. 364 if f.WidthPresent && f.Width > width && f.Minus { 365 f.writePadding(f.Width - width) 366 } 367 } 368 369 // fmt_sx formats a string as a hexadecimal encoding of its bytes. 370 func (f *formatInfo) fmt_sx(s, digits string) { 371 f.fmt_sbx(s, nil, digits) 372 } 373 374 // fmt_bx formats a byte slice as a hexadecimal encoding of its bytes. 375 func (f *formatInfo) fmt_bx(b []byte, digits string) { 376 f.fmt_sbx("", b, digits) 377 } 378 379 // fmt_q formats a string as a double-quoted, escaped Go string constant. 380 // If f.sharp is set a raw (backquoted) string may be returned instead 381 // if the string does not contain any control characters other than tab. 382 func (f *formatInfo) fmt_q(s string) { 383 s = f.truncate(s) 384 if f.Sharp && strconv.CanBackquote(s) { 385 f.padString("`" + s + "`") 386 return 387 } 388 buf := f.intbuf[:0] 389 if f.Plus { 390 f.pad(strconv.AppendQuoteToASCII(buf, s)) 391 } else { 392 f.pad(strconv.AppendQuote(buf, s)) 393 } 394 } 395 396 // fmt_c formats an integer as a Unicode character. 397 // If the character is not valid Unicode, it will print '\ufffd'. 398 func (f *formatInfo) fmt_c(c uint64) { 399 r := rune(c) 400 if c > utf8.MaxRune { 401 r = utf8.RuneError 402 } 403 buf := f.intbuf[:0] 404 w := utf8.EncodeRune(buf[:utf8.UTFMax], r) 405 f.pad(buf[:w]) 406 } 407 408 // fmt_qc formats an integer as a single-quoted, escaped Go character constant. 409 // If the character is not valid Unicode, it will print '\ufffd'. 410 func (f *formatInfo) fmt_qc(c uint64) { 411 r := rune(c) 412 if c > utf8.MaxRune { 413 r = utf8.RuneError 414 } 415 buf := f.intbuf[:0] 416 if f.Plus { 417 f.pad(strconv.AppendQuoteRuneToASCII(buf, r)) 418 } else { 419 f.pad(strconv.AppendQuoteRune(buf, r)) 420 } 421 } 422 423 // fmt_float formats a float64. It assumes that verb is a valid format specifier 424 // for strconv.AppendFloat and therefore fits into a byte. 425 func (f *formatInfo) fmt_float(v float64, size int, verb rune, prec int) { 426 // Explicit precision in format specifier overrules default precision. 427 if f.PrecPresent { 428 prec = f.Prec 429 } 430 // Format number, reserving space for leading + sign if needed. 431 num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size) 432 if num[1] == '-' || num[1] == '+' { 433 num = num[1:] 434 } else { 435 num[0] = '+' 436 } 437 // f.space means to add a leading space instead of a "+" sign unless 438 // the sign is explicitly asked for by f.plus. 439 if f.Space && num[0] == '+' && !f.Plus { 440 num[0] = ' ' 441 } 442 // Special handling for infinities and NaN, 443 // which don't look like a number so shouldn't be padded with zeros. 444 if num[1] == 'I' || num[1] == 'N' { 445 oldZero := f.Zero 446 f.Zero = false 447 // Remove sign before NaN if not asked for. 448 if num[1] == 'N' && !f.Space && !f.Plus { 449 num = num[1:] 450 } 451 f.pad(num) 452 f.Zero = oldZero 453 return 454 } 455 // The sharp flag forces printing a decimal point for non-binary formats 456 // and retains trailing zeros, which we may need to restore. 457 if f.Sharp && verb != 'b' { 458 digits := 0 459 switch verb { 460 case 'v', 'g', 'G': 461 digits = prec 462 // If no precision is set explicitly use a precision of 6. 463 if digits == -1 { 464 digits = 6 465 } 466 } 467 468 // Buffer pre-allocated with enough room for 469 // exponent notations of the form "e+123". 470 var tailBuf [5]byte 471 tail := tailBuf[:0] 472 473 hasDecimalPoint := false 474 // Starting from i = 1 to skip sign at num[0]. 475 for i := 1; i < len(num); i++ { 476 switch num[i] { 477 case '.': 478 hasDecimalPoint = true 479 case 'e', 'E': 480 tail = append(tail, num[i:]...) 481 num = num[:i] 482 default: 483 digits-- 484 } 485 } 486 if !hasDecimalPoint { 487 num = append(num, '.') 488 } 489 for digits > 0 { 490 num = append(num, '0') 491 digits-- 492 } 493 num = append(num, tail...) 494 } 495 // We want a sign if asked for and if the sign is not positive. 496 if f.Plus || num[0] != '+' { 497 // If we're zero padding to the left we want the sign before the leading zeros. 498 // Achieve this by writing the sign out and then padding the unsigned number. 499 if f.Zero && f.WidthPresent && f.Width > len(num) { 500 f.buf.WriteByte(num[0]) 501 f.writePadding(f.Width - len(num)) 502 f.buf.Write(num[1:]) 503 return 504 } 505 f.pad(num) 506 return 507 } 508 // No sign to show and the number is positive; just print the unsigned number. 509 f.pad(num[1:]) 510 }