2014-04-11 Marc Glisse <marc.glisse@inria.fr>
[official-gcc.git] / libgo / go / time / zoneinfo_plan9.go
blob0e8f3811bedc1d4d1919e9c717651dfffa5cb881
1 // Copyright 2011 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.
5 // Parse Plan 9 timezone(2) files.
7 package time
9 import (
10 "errors"
11 "runtime"
12 "syscall"
15 func isSpace(r rune) bool {
16 return r == ' ' || r == '\t' || r == '\n'
19 // Copied from strings to avoid a dependency.
20 func fields(s string) []string {
21 // First count the fields.
22 n := 0
23 inField := false
24 for _, rune := range s {
25 wasInField := inField
26 inField = !isSpace(rune)
27 if inField && !wasInField {
28 n++
32 // Now create them.
33 a := make([]string, n)
34 na := 0
35 fieldStart := -1 // Set to -1 when looking for start of field.
36 for i, rune := range s {
37 if isSpace(rune) {
38 if fieldStart >= 0 {
39 a[na] = s[fieldStart:i]
40 na++
41 fieldStart = -1
43 } else if fieldStart == -1 {
44 fieldStart = i
47 if fieldStart >= 0 { // Last field might end at EOF.
48 a[na] = s[fieldStart:]
50 return a
53 func loadZoneDataPlan9(s string) (l *Location, err error) {
54 f := fields(s)
55 if len(f) < 4 {
56 if len(f) == 2 && f[0] == "GMT" {
57 return UTC, nil
59 return nil, badData
62 var zones [2]zone
64 // standard timezone offset
65 o, err := atoi(f[1])
66 if err != nil {
67 return nil, badData
69 zones[0] = zone{name: f[0], offset: o, isDST: false}
71 // alternate timezone offset
72 o, err = atoi(f[3])
73 if err != nil {
74 return nil, badData
76 zones[1] = zone{name: f[2], offset: o, isDST: true}
78 // transition time pairs
79 var tx []zoneTrans
80 f = f[4:]
81 for i := 0; i < len(f); i++ {
82 zi := 0
83 if i%2 == 0 {
84 zi = 1
86 t, err := atoi(f[i])
87 if err != nil {
88 return nil, badData
90 t -= zones[0].offset
91 tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)})
94 // Committed to succeed.
95 l = &Location{zone: zones[:], tx: tx}
97 // Fill in the cache with information about right now,
98 // since that will be the most common lookup.
99 sec, _ := now()
100 for i := range tx {
101 if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
102 l.cacheStart = tx[i].when
103 l.cacheEnd = 1<<63 - 1
104 if i+1 < len(tx) {
105 l.cacheEnd = tx[i+1].when
107 l.cacheZone = &l.zone[tx[i].index]
111 return l, nil
114 func loadZoneFilePlan9(name string) (*Location, error) {
115 b, err := readFile(name)
116 if err != nil {
117 return nil, err
119 return loadZoneDataPlan9(string(b))
122 func initTestingZone() {
123 z, err := loadLocation("America/Los_Angeles")
124 if err != nil {
125 panic("cannot load America/Los_Angeles for testing: " + err.Error())
127 z.name = "Local"
128 localLoc = *z
131 func initLocal() {
132 t, ok := syscall.Getenv("timezone")
133 if ok {
134 if z, err := loadZoneDataPlan9(t); err == nil {
135 localLoc = *z
136 return
138 } else {
139 if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil {
140 localLoc = *z
141 localLoc.name = "Local"
142 return
146 // Fall back to UTC.
147 localLoc.name = "UTC"
150 func loadLocation(name string) (*Location, error) {
151 if z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name); err == nil {
152 z.name = name
153 return z, nil
155 return nil, errors.New("unknown time zone " + name)
158 func forceZipFileForTesting(zipOnly bool) {
159 // We only use the zip file anyway.