changeset 256 | 6d9efbef00a9 |
parent 242 | 2a9ec03fe5a1 |
child 260 | 445e01aede7e |
255:4f153a23adab | 256:6d9efbef00a9 |
---|---|
6 |
6 |
7 // BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer. |
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. |
8 // BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used. |
9 |
9 |
10 import ( |
10 import ( |
11 "bytes" |
|
11 "fmt" |
12 "fmt" |
12 "io" |
13 "io" |
13 "log" |
14 "log" |
14 "os" |
15 "os" |
15 "regexp" |
16 "regexp" |
17 "sort" |
|
16 "strconv" |
18 "strconv" |
17 "strings" |
19 "strings" |
18 "time" |
20 "time" |
19 "unicode/utf8" |
21 "unicode/utf8" |
20 ) |
22 ) |
67 // Stores the comments per key. |
69 // Stores the comments per key. |
68 c map[string][]string |
70 c map[string][]string |
69 |
71 |
70 // Stores the keys in order of appearance. |
72 // Stores the keys in order of appearance. |
71 k []string |
73 k []string |
74 |
|
75 // WriteSeparator specifies the separator of key and value while writing the properties. |
|
76 WriteSeparator string |
|
72 } |
77 } |
73 |
78 |
74 // NewProperties creates a new Properties struct with the default |
79 // NewProperties creates a new Properties struct with the default |
75 // configuration for "${key}" expressions. |
80 // configuration for "${key}" expressions. |
76 func NewProperties() *Properties { |
81 func NewProperties() *Properties { |
109 |
114 |
110 // we guarantee that the expanded value is free of |
115 // we guarantee that the expanded value is free of |
111 // circular references and malformed expressions |
116 // circular references and malformed expressions |
112 // so we panic if we still get an error here. |
117 // so we panic if we still get an error here. |
113 if err != nil { |
118 if err != nil { |
114 ErrorHandler(fmt.Errorf("%s in %q", err, key+" = "+v)) |
119 ErrorHandler(err) |
115 } |
120 } |
116 |
121 |
117 return expanded, true |
122 return expanded, true |
118 } |
123 } |
119 |
124 |
584 s = fmt.Sprintf("%s%s = %s\n", s, key, value) |
589 s = fmt.Sprintf("%s%s = %s\n", s, key, value) |
585 } |
590 } |
586 return s |
591 return s |
587 } |
592 } |
588 |
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 |
|
589 // Write writes all unexpanded 'key = value' pairs to the given writer. |
600 // Write writes all unexpanded 'key = value' pairs to the given writer. |
590 // Write returns the number of bytes written and any write error encountered. |
601 // Write returns the number of bytes written and any write error encountered. |
591 func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) { |
602 func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) { |
592 return p.WriteComment(w, "", enc) |
603 return p.WriteComment(w, "", enc) |
593 } |
604 } |
624 } |
635 } |
625 n += x |
636 n += x |
626 } |
637 } |
627 |
638 |
628 for _, c := range comments { |
639 for _, c := range comments { |
629 x, err = fmt.Fprintf(w, "%s%s\n", prefix, encode(c, "", enc)) |
640 x, err = fmt.Fprintf(w, "%s%s\n", prefix, c) |
630 if err != nil { |
641 if err != nil { |
631 return |
642 return |
632 } |
643 } |
633 n += x |
644 n += x |
634 } |
645 } |
635 } |
646 } |
636 } |
647 } |
637 } |
648 } |
638 |
649 sep := " = " |
639 x, err = fmt.Fprintf(w, "%s = %s\n", encode(key, " :", enc), encode(value, "", enc)) |
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)) |
|
640 if err != nil { |
654 if err != nil { |
641 return |
655 return |
642 } |
656 } |
643 n += x |
657 n += x |
644 } |
658 } |
751 |
765 |
752 // 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) |
766 // 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) |
753 |
767 |
754 for _, k := range keys { |
768 for _, k := range keys { |
755 if key == k { |
769 if key == k { |
756 return "", fmt.Errorf("circular reference") |
770 var b bytes.Buffer |
771 b.WriteString("circular reference in:\n") |
|
772 for _, k1 := range keys { |
|
773 fmt.Fprintf(&b, "%s=%s\n", k1, values[k1]) |
|
774 } |
|
775 return "", fmt.Errorf(b.String()) |
|
757 } |
776 } |
758 } |
777 } |
759 |
778 |
760 val, ok := values[key] |
779 val, ok := values[key] |
761 if !ok { |
780 if !ok { |
818 return "\\n" |
837 return "\\n" |
819 case '\r': |
838 case '\r': |
820 return "\\r" |
839 return "\\r" |
821 case '\t': |
840 case '\t': |
822 return "\\t" |
841 return "\\t" |
842 case '\\': |
|
843 return "\\\\" |
|
823 default: |
844 default: |
824 if strings.ContainsRune(special, r) { |
845 if strings.ContainsRune(special, r) { |
825 return "\\" + string(r) |
846 return "\\" + string(r) |
826 } |
847 } |
827 return string(r) |
848 return string(r) |