podman

Форк
0
848 строк · 22.7 Кб
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
}
849

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.