properties.go (23262B)
1 // Copyright 2013-2022 Frank Schroeder. 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 properties 6 7 // BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer. 8 // BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used. 9 10 import ( 11 "bytes" 12 "fmt" 13 "io" 14 "log" 15 "os" 16 "regexp" 17 "sort" 18 "strconv" 19 "strings" 20 "time" 21 "unicode/utf8" 22 ) 23 24 const maxExpansionDepth = 64 25 26 // ErrorHandlerFunc defines the type of function which handles failures 27 // of the MustXXX() functions. An error handler function must exit 28 // the application after handling the error. 29 type ErrorHandlerFunc func(error) 30 31 // ErrorHandler is the function which handles failures of the MustXXX() 32 // functions. The default is LogFatalHandler. 33 var ErrorHandler ErrorHandlerFunc = LogFatalHandler 34 35 // LogHandlerFunc defines the function prototype for logging errors. 36 type LogHandlerFunc func(fmt string, args ...interface{}) 37 38 // LogPrintf defines a log handler which uses log.Printf. 39 var LogPrintf LogHandlerFunc = log.Printf 40 41 // LogFatalHandler handles the error by logging a fatal error and exiting. 42 func LogFatalHandler(err error) { 43 log.Fatal(err) 44 } 45 46 // PanicHandler handles the error by panicking. 47 func PanicHandler(err error) { 48 panic(err) 49 } 50 51 // ----------------------------------------------------------------------------- 52 53 // A Properties contains the key/value pairs from the properties input. 54 // All values are stored in unexpanded form and are expanded at runtime 55 type Properties struct { 56 // Pre-/Postfix for property expansion. 57 Prefix string 58 Postfix string 59 60 // DisableExpansion controls the expansion of properties on Get() 61 // and the check for circular references on Set(). When set to 62 // true Properties behaves like a simple key/value store and does 63 // not check for circular references on Get() or on Set(). 64 DisableExpansion bool 65 66 // Stores the key/value pairs 67 m map[string]string 68 69 // Stores the comments per key. 70 c map[string][]string 71 72 // Stores the keys in order of appearance. 73 k []string 74 75 // WriteSeparator specifies the separator of key and value while writing the properties. 76 WriteSeparator string 77 } 78 79 // NewProperties creates a new Properties struct with the default 80 // configuration for "${key}" expressions. 81 func NewProperties() *Properties { 82 return &Properties{ 83 Prefix: "${", 84 Postfix: "}", 85 m: map[string]string{}, 86 c: map[string][]string{}, 87 k: []string{}, 88 } 89 } 90 91 // Load reads a buffer into the given Properties struct. 92 func (p *Properties) Load(buf []byte, enc Encoding) error { 93 l := &Loader{Encoding: enc, DisableExpansion: p.DisableExpansion} 94 newProperties, err := l.LoadBytes(buf) 95 if err != nil { 96 return err 97 } 98 p.Merge(newProperties) 99 return nil 100 } 101 102 // Get returns the expanded value for the given key if exists. 103 // Otherwise, ok is false. 104 func (p *Properties) Get(key string) (value string, ok bool) { 105 v, ok := p.m[key] 106 if p.DisableExpansion { 107 return v, ok 108 } 109 if !ok { 110 return "", false 111 } 112 113 expanded, err := p.expand(key, v) 114 115 // we guarantee that the expanded value is free of 116 // circular references and malformed expressions 117 // so we panic if we still get an error here. 118 if err != nil { 119 ErrorHandler(err) 120 } 121 122 return expanded, true 123 } 124 125 // MustGet returns the expanded value for the given key if exists. 126 // Otherwise, it panics. 127 func (p *Properties) MustGet(key string) string { 128 if v, ok := p.Get(key); ok { 129 return v 130 } 131 ErrorHandler(invalidKeyError(key)) 132 panic("ErrorHandler should exit") 133 } 134 135 // ---------------------------------------------------------------------------- 136 137 // ClearComments removes the comments for all keys. 138 func (p *Properties) ClearComments() { 139 p.c = map[string][]string{} 140 } 141 142 // ---------------------------------------------------------------------------- 143 144 // GetComment returns the last comment before the given key or an empty string. 145 func (p *Properties) GetComment(key string) string { 146 comments, ok := p.c[key] 147 if !ok || len(comments) == 0 { 148 return "" 149 } 150 return comments[len(comments)-1] 151 } 152 153 // ---------------------------------------------------------------------------- 154 155 // GetComments returns all comments that appeared before the given key or nil. 156 func (p *Properties) GetComments(key string) []string { 157 if comments, ok := p.c[key]; ok { 158 return comments 159 } 160 return nil 161 } 162 163 // ---------------------------------------------------------------------------- 164 165 // SetComment sets the comment for the key. 166 func (p *Properties) SetComment(key, comment string) { 167 p.c[key] = []string{comment} 168 } 169 170 // ---------------------------------------------------------------------------- 171 172 // SetComments sets the comments for the key. If the comments are nil then 173 // all comments for this key are deleted. 174 func (p *Properties) SetComments(key string, comments []string) { 175 if comments == nil { 176 delete(p.c, key) 177 return 178 } 179 p.c[key] = comments 180 } 181 182 // ---------------------------------------------------------------------------- 183 184 // GetBool checks if the expanded value is one of '1', 'yes', 185 // 'true' or 'on' if the key exists. The comparison is case-insensitive. 186 // If the key does not exist the default value is returned. 187 func (p *Properties) GetBool(key string, def bool) bool { 188 v, err := p.getBool(key) 189 if err != nil { 190 return def 191 } 192 return v 193 } 194 195 // MustGetBool checks if the expanded value is one of '1', 'yes', 196 // 'true' or 'on' if the key exists. The comparison is case-insensitive. 197 // If the key does not exist the function panics. 198 func (p *Properties) MustGetBool(key string) bool { 199 v, err := p.getBool(key) 200 if err != nil { 201 ErrorHandler(err) 202 } 203 return v 204 } 205 206 func (p *Properties) getBool(key string) (value bool, err error) { 207 if v, ok := p.Get(key); ok { 208 return boolVal(v), nil 209 } 210 return false, invalidKeyError(key) 211 } 212 213 func boolVal(v string) bool { 214 v = strings.ToLower(v) 215 return v == "1" || v == "true" || v == "yes" || v == "on" 216 } 217 218 // ---------------------------------------------------------------------------- 219 220 // GetDuration parses the expanded value as an time.Duration (in ns) if the 221 // key exists. If key does not exist or the value cannot be parsed the default 222 // value is returned. In almost all cases you want to use GetParsedDuration(). 223 func (p *Properties) GetDuration(key string, def time.Duration) time.Duration { 224 v, err := p.getInt64(key) 225 if err != nil { 226 return def 227 } 228 return time.Duration(v) 229 } 230 231 // MustGetDuration parses the expanded value as an time.Duration (in ns) if 232 // the key exists. If key does not exist or the value cannot be parsed the 233 // function panics. In almost all cases you want to use MustGetParsedDuration(). 234 func (p *Properties) MustGetDuration(key string) time.Duration { 235 v, err := p.getInt64(key) 236 if err != nil { 237 ErrorHandler(err) 238 } 239 return time.Duration(v) 240 } 241 242 // ---------------------------------------------------------------------------- 243 244 // GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists. 245 // If key does not exist or the value cannot be parsed the default 246 // value is returned. 247 func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration { 248 s, ok := p.Get(key) 249 if !ok { 250 return def 251 } 252 v, err := time.ParseDuration(s) 253 if err != nil { 254 return def 255 } 256 return v 257 } 258 259 // MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists. 260 // If key does not exist or the value cannot be parsed the function panics. 261 func (p *Properties) MustGetParsedDuration(key string) time.Duration { 262 s, ok := p.Get(key) 263 if !ok { 264 ErrorHandler(invalidKeyError(key)) 265 } 266 v, err := time.ParseDuration(s) 267 if err != nil { 268 ErrorHandler(err) 269 } 270 return v 271 } 272 273 // ---------------------------------------------------------------------------- 274 275 // GetFloat64 parses the expanded value as a float64 if the key exists. 276 // If key does not exist or the value cannot be parsed the default 277 // value is returned. 278 func (p *Properties) GetFloat64(key string, def float64) float64 { 279 v, err := p.getFloat64(key) 280 if err != nil { 281 return def 282 } 283 return v 284 } 285 286 // MustGetFloat64 parses the expanded value as a float64 if the key exists. 287 // If key does not exist or the value cannot be parsed the function panics. 288 func (p *Properties) MustGetFloat64(key string) float64 { 289 v, err := p.getFloat64(key) 290 if err != nil { 291 ErrorHandler(err) 292 } 293 return v 294 } 295 296 func (p *Properties) getFloat64(key string) (value float64, err error) { 297 if v, ok := p.Get(key); ok { 298 value, err = strconv.ParseFloat(v, 64) 299 if err != nil { 300 return 0, err 301 } 302 return value, nil 303 } 304 return 0, invalidKeyError(key) 305 } 306 307 // ---------------------------------------------------------------------------- 308 309 // GetInt parses the expanded value as an int if the key exists. 310 // If key does not exist or the value cannot be parsed the default 311 // value is returned. If the value does not fit into an int the 312 // function panics with an out of range error. 313 func (p *Properties) GetInt(key string, def int) int { 314 v, err := p.getInt64(key) 315 if err != nil { 316 return def 317 } 318 return intRangeCheck(key, v) 319 } 320 321 // MustGetInt parses the expanded value as an int if the key exists. 322 // If key does not exist or the value cannot be parsed the function panics. 323 // If the value does not fit into an int the function panics with 324 // an out of range error. 325 func (p *Properties) MustGetInt(key string) int { 326 v, err := p.getInt64(key) 327 if err != nil { 328 ErrorHandler(err) 329 } 330 return intRangeCheck(key, v) 331 } 332 333 // ---------------------------------------------------------------------------- 334 335 // GetInt64 parses the expanded value as an int64 if the key exists. 336 // If key does not exist or the value cannot be parsed the default 337 // value is returned. 338 func (p *Properties) GetInt64(key string, def int64) int64 { 339 v, err := p.getInt64(key) 340 if err != nil { 341 return def 342 } 343 return v 344 } 345 346 // MustGetInt64 parses the expanded value as an int if the key exists. 347 // If key does not exist or the value cannot be parsed the function panics. 348 func (p *Properties) MustGetInt64(key string) int64 { 349 v, err := p.getInt64(key) 350 if err != nil { 351 ErrorHandler(err) 352 } 353 return v 354 } 355 356 func (p *Properties) getInt64(key string) (value int64, err error) { 357 if v, ok := p.Get(key); ok { 358 value, err = strconv.ParseInt(v, 10, 64) 359 if err != nil { 360 return 0, err 361 } 362 return value, nil 363 } 364 return 0, invalidKeyError(key) 365 } 366 367 // ---------------------------------------------------------------------------- 368 369 // GetUint parses the expanded value as an uint if the key exists. 370 // If key does not exist or the value cannot be parsed the default 371 // value is returned. If the value does not fit into an int the 372 // function panics with an out of range error. 373 func (p *Properties) GetUint(key string, def uint) uint { 374 v, err := p.getUint64(key) 375 if err != nil { 376 return def 377 } 378 return uintRangeCheck(key, v) 379 } 380 381 // MustGetUint parses the expanded value as an int if the key exists. 382 // If key does not exist or the value cannot be parsed the function panics. 383 // If the value does not fit into an int the function panics with 384 // an out of range error. 385 func (p *Properties) MustGetUint(key string) uint { 386 v, err := p.getUint64(key) 387 if err != nil { 388 ErrorHandler(err) 389 } 390 return uintRangeCheck(key, v) 391 } 392 393 // ---------------------------------------------------------------------------- 394 395 // GetUint64 parses the expanded value as an uint64 if the key exists. 396 // If key does not exist or the value cannot be parsed the default 397 // value is returned. 398 func (p *Properties) GetUint64(key string, def uint64) uint64 { 399 v, err := p.getUint64(key) 400 if err != nil { 401 return def 402 } 403 return v 404 } 405 406 // MustGetUint64 parses the expanded value as an int if the key exists. 407 // If key does not exist or the value cannot be parsed the function panics. 408 func (p *Properties) MustGetUint64(key string) uint64 { 409 v, err := p.getUint64(key) 410 if err != nil { 411 ErrorHandler(err) 412 } 413 return v 414 } 415 416 func (p *Properties) getUint64(key string) (value uint64, err error) { 417 if v, ok := p.Get(key); ok { 418 value, err = strconv.ParseUint(v, 10, 64) 419 if err != nil { 420 return 0, err 421 } 422 return value, nil 423 } 424 return 0, invalidKeyError(key) 425 } 426 427 // ---------------------------------------------------------------------------- 428 429 // GetString returns the expanded value for the given key if exists or 430 // the default value otherwise. 431 func (p *Properties) GetString(key, def string) string { 432 if v, ok := p.Get(key); ok { 433 return v 434 } 435 return def 436 } 437 438 // MustGetString returns the expanded value for the given key if exists or 439 // panics otherwise. 440 func (p *Properties) MustGetString(key string) string { 441 if v, ok := p.Get(key); ok { 442 return v 443 } 444 ErrorHandler(invalidKeyError(key)) 445 panic("ErrorHandler should exit") 446 } 447 448 // ---------------------------------------------------------------------------- 449 450 // Filter returns a new properties object which contains all properties 451 // for which the key matches the pattern. 452 func (p *Properties) Filter(pattern string) (*Properties, error) { 453 re, err := regexp.Compile(pattern) 454 if err != nil { 455 return nil, err 456 } 457 458 return p.FilterRegexp(re), nil 459 } 460 461 // FilterRegexp returns a new properties object which contains all properties 462 // for which the key matches the regular expression. 463 func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties { 464 pp := NewProperties() 465 for _, k := range p.k { 466 if re.MatchString(k) { 467 // TODO(fs): we are ignoring the error which flags a circular reference. 468 // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed) 469 pp.Set(k, p.m[k]) 470 } 471 } 472 return pp 473 } 474 475 // FilterPrefix returns a new properties object with a subset of all keys 476 // with the given prefix. 477 func (p *Properties) FilterPrefix(prefix string) *Properties { 478 pp := NewProperties() 479 for _, k := range p.k { 480 if strings.HasPrefix(k, prefix) { 481 // TODO(fs): we are ignoring the error which flags a circular reference. 482 // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed) 483 pp.Set(k, p.m[k]) 484 } 485 } 486 return pp 487 } 488 489 // FilterStripPrefix returns a new properties object with a subset of all keys 490 // with the given prefix and the prefix removed from the keys. 491 func (p *Properties) FilterStripPrefix(prefix string) *Properties { 492 pp := NewProperties() 493 n := len(prefix) 494 for _, k := range p.k { 495 if len(k) > len(prefix) && strings.HasPrefix(k, prefix) { 496 // TODO(fs): we are ignoring the error which flags a circular reference. 497 // TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference 498 // TODO(fs): this function should probably return an error but the signature is fixed 499 pp.Set(k[n:], p.m[k]) 500 } 501 } 502 return pp 503 } 504 505 // Len returns the number of keys. 506 func (p *Properties) Len() int { 507 return len(p.m) 508 } 509 510 // Keys returns all keys in the same order as in the input. 511 func (p *Properties) Keys() []string { 512 keys := make([]string, len(p.k)) 513 copy(keys, p.k) 514 return keys 515 } 516 517 // Set sets the property key to the corresponding value. 518 // If a value for key existed before then ok is true and prev 519 // contains the previous value. If the value contains a 520 // circular reference or a malformed expression then 521 // an error is returned. 522 // An empty key is silently ignored. 523 func (p *Properties) Set(key, value string) (prev string, ok bool, err error) { 524 if key == "" { 525 return "", false, nil 526 } 527 528 // if expansion is disabled we allow circular references 529 if p.DisableExpansion { 530 prev, ok = p.Get(key) 531 p.m[key] = value 532 if !ok { 533 p.k = append(p.k, key) 534 } 535 return prev, ok, nil 536 } 537 538 // to check for a circular reference we temporarily need 539 // to set the new value. If there is an error then revert 540 // to the previous state. Only if all tests are successful 541 // then we add the key to the p.k list. 542 prev, ok = p.Get(key) 543 p.m[key] = value 544 545 // now check for a circular reference 546 _, err = p.expand(key, value) 547 if err != nil { 548 549 // revert to the previous state 550 if ok { 551 p.m[key] = prev 552 } else { 553 delete(p.m, key) 554 } 555 556 return "", false, err 557 } 558 559 if !ok { 560 p.k = append(p.k, key) 561 } 562 563 return prev, ok, nil 564 } 565 566 // SetValue sets property key to the default string value 567 // as defined by fmt.Sprintf("%v"). 568 func (p *Properties) SetValue(key string, value interface{}) error { 569 _, _, err := p.Set(key, fmt.Sprintf("%v", value)) 570 return err 571 } 572 573 // MustSet sets the property key to the corresponding value. 574 // If a value for key existed before then ok is true and prev 575 // contains the previous value. An empty key is silently ignored. 576 func (p *Properties) MustSet(key, value string) (prev string, ok bool) { 577 prev, ok, err := p.Set(key, value) 578 if err != nil { 579 ErrorHandler(err) 580 } 581 return prev, ok 582 } 583 584 // String returns a string of all expanded 'key = value' pairs. 585 func (p *Properties) String() string { 586 var s string 587 for _, key := range p.k { 588 value, _ := p.Get(key) 589 s = fmt.Sprintf("%s%s = %s\n", s, key, value) 590 } 591 return s 592 } 593 594 // Sort sorts the properties keys in alphabetical order. 595 // This is helpfully before writing the properties. 596 func (p *Properties) Sort() { 597 sort.Strings(p.k) 598 } 599 600 // Write writes all unexpanded 'key = value' pairs to the given writer. 601 // Write returns the number of bytes written and any write error encountered. 602 func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) { 603 return p.WriteComment(w, "", enc) 604 } 605 606 // WriteComment writes all unexpanced 'key = value' pairs to the given writer. 607 // If prefix is not empty then comments are written with a blank line and the 608 // given prefix. The prefix should be either "# " or "! " to be compatible with 609 // the properties file format. Otherwise, the properties parser will not be 610 // able to read the file back in. It returns the number of bytes written and 611 // any write error encountered. 612 func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) { 613 var x int 614 615 for _, key := range p.k { 616 value := p.m[key] 617 618 if prefix != "" { 619 if comments, ok := p.c[key]; ok { 620 // don't print comments if they are all empty 621 allEmpty := true 622 for _, c := range comments { 623 if c != "" { 624 allEmpty = false 625 break 626 } 627 } 628 629 if !allEmpty { 630 // add a blank line between entries but not at the top 631 if len(comments) > 0 && n > 0 { 632 x, err = fmt.Fprintln(w) 633 if err != nil { 634 return 635 } 636 n += x 637 } 638 639 for _, c := range comments { 640 x, err = fmt.Fprintf(w, "%s%s\n", prefix, c) 641 if err != nil { 642 return 643 } 644 n += x 645 } 646 } 647 } 648 } 649 sep := " = " 650 if p.WriteSeparator != "" { 651 sep = p.WriteSeparator 652 } 653 x, err = fmt.Fprintf(w, "%s%s%s\n", encode(key, " :", enc), sep, encode(value, "", enc)) 654 if err != nil { 655 return 656 } 657 n += x 658 } 659 return 660 } 661 662 // Map returns a copy of the properties as a map. 663 func (p *Properties) Map() map[string]string { 664 m := make(map[string]string) 665 for k, v := range p.m { 666 m[k] = v 667 } 668 return m 669 } 670 671 // FilterFunc returns a copy of the properties which includes the values which passed all filters. 672 func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties { 673 pp := NewProperties() 674 outer: 675 for k, v := range p.m { 676 for _, f := range filters { 677 if !f(k, v) { 678 continue outer 679 } 680 pp.Set(k, v) 681 } 682 } 683 return pp 684 } 685 686 // ---------------------------------------------------------------------------- 687 688 // Delete removes the key and its comments. 689 func (p *Properties) Delete(key string) { 690 delete(p.m, key) 691 delete(p.c, key) 692 newKeys := []string{} 693 for _, k := range p.k { 694 if k != key { 695 newKeys = append(newKeys, k) 696 } 697 } 698 p.k = newKeys 699 } 700 701 // Merge merges properties, comments and keys from other *Properties into p 702 func (p *Properties) Merge(other *Properties) { 703 for _, k := range other.k { 704 if _, ok := p.m[k]; !ok { 705 p.k = append(p.k, k) 706 } 707 } 708 for k, v := range other.m { 709 p.m[k] = v 710 } 711 for k, v := range other.c { 712 p.c[k] = v 713 } 714 } 715 716 // ---------------------------------------------------------------------------- 717 718 // check expands all values and returns an error if a circular reference or 719 // a malformed expression was found. 720 func (p *Properties) check() error { 721 for key, value := range p.m { 722 if _, err := p.expand(key, value); err != nil { 723 return err 724 } 725 } 726 return nil 727 } 728 729 func (p *Properties) expand(key, input string) (string, error) { 730 // no pre/postfix -> nothing to expand 731 if p.Prefix == "" && p.Postfix == "" { 732 return input, nil 733 } 734 735 return expand(input, []string{key}, p.Prefix, p.Postfix, p.m) 736 } 737 738 // expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values. 739 // The function keeps track of the keys that were already expanded and stops if it 740 // detects a circular reference or a malformed expression of the form '(prefix)key'. 741 func expand(s string, keys []string, prefix, postfix string, values map[string]string) (string, error) { 742 if len(keys) > maxExpansionDepth { 743 return "", fmt.Errorf("expansion too deep") 744 } 745 746 for { 747 start := strings.Index(s, prefix) 748 if start == -1 { 749 return s, nil 750 } 751 752 keyStart := start + len(prefix) 753 keyLen := strings.Index(s[keyStart:], postfix) 754 if keyLen == -1 { 755 return "", fmt.Errorf("malformed expression") 756 } 757 758 end := keyStart + keyLen + len(postfix) - 1 759 key := s[keyStart : keyStart+keyLen] 760 761 // fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key) 762 763 for _, k := range keys { 764 if key == k { 765 var b bytes.Buffer 766 b.WriteString("circular reference in:\n") 767 for _, k1 := range keys { 768 fmt.Fprintf(&b, "%s=%s\n", k1, values[k1]) 769 } 770 return "", fmt.Errorf(b.String()) 771 } 772 } 773 774 val, ok := values[key] 775 if !ok { 776 val = os.Getenv(key) 777 } 778 new_val, err := expand(val, append(keys, key), prefix, postfix, values) 779 if err != nil { 780 return "", err 781 } 782 s = s[:start] + new_val + s[end+1:] 783 } 784 } 785 786 // encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters. 787 func encode(s string, special string, enc Encoding) string { 788 switch enc { 789 case UTF8: 790 return encodeUtf8(s, special) 791 case ISO_8859_1: 792 return encodeIso(s, special) 793 default: 794 panic(fmt.Sprintf("unsupported encoding %v", enc)) 795 } 796 } 797 798 func encodeUtf8(s string, special string) string { 799 v := "" 800 for pos := 0; pos < len(s); { 801 r, w := utf8.DecodeRuneInString(s[pos:]) 802 pos += w 803 v += escape(r, special) 804 } 805 return v 806 } 807 808 func encodeIso(s string, special string) string { 809 var r rune 810 var w int 811 var v string 812 for pos := 0; pos < len(s); { 813 switch r, w = utf8.DecodeRuneInString(s[pos:]); { 814 case r < 1<<8: // single byte rune -> escape special chars only 815 v += escape(r, special) 816 case r < 1<<16: // two byte rune -> unicode literal 817 v += fmt.Sprintf("\\u%04x", r) 818 default: // more than two bytes per rune -> can't encode 819 v += "?" 820 } 821 pos += w 822 } 823 return v 824 } 825 826 func escape(r rune, special string) string { 827 switch r { 828 case '\f': 829 return "\\f" 830 case '\n': 831 return "\\n" 832 case '\r': 833 return "\\r" 834 case '\t': 835 return "\\t" 836 case '\\': 837 return "\\\\" 838 default: 839 if strings.ContainsRune(special, r) { 840 return "\\" + string(r) 841 } 842 return string(r) 843 } 844 } 845 846 func invalidKeyError(key string) error { 847 return fmt.Errorf("unknown property: %s", key) 848 }