mirror of
https://github.com/golang/go
synced 2024-11-12 04:40:22 -07:00
assorted changes:
- use a lock instead of a thread in once avoids deadlock in recursive once calls - implement os.Setenv - remove "export" from some scripts - remove _ from names in time package - fix time test for non-MTV machines R=r DELTA=265 (87 added, 58 deleted, 120 changed) OCL=25057 CL=25057
This commit is contained in:
parent
55d13cf139
commit
ff3173849e
@ -94,11 +94,12 @@ test: test.files
|
||||
|
||||
bignum.6: fmt.dirinstall
|
||||
bufio.6: io.dirinstall os.dirinstall
|
||||
exec.6: os.dirinstall
|
||||
flag.6: fmt.dirinstall
|
||||
log.6: fmt.dirinstall io.dirinstall os.dirinstall time.dirinstall
|
||||
testing.6: flag.install fmt.dirinstall
|
||||
once.6: sync.dirinstall
|
||||
strings.6: utf8.install
|
||||
exec.6: os.dirinstall
|
||||
testing.6: flag.install fmt.dirinstall
|
||||
|
||||
fmt.dirinstall: io.dirinstall reflect.dirinstall strconv.dirinstall
|
||||
hash.dirinstall: os.dirinstall
|
||||
@ -108,7 +109,7 @@ json.dirinstall: container/array.dirinstall fmt.dirinstall io.dirinstall math.di
|
||||
strconv.dirinstall strings.install utf8.install
|
||||
# TODO(rsc): net is not supposed to depend on fmt or strings or strconv
|
||||
net.dirinstall: fmt.dirinstall once.install os.dirinstall strconv.dirinstall strings.install
|
||||
os.dirinstall: syscall.dirinstall
|
||||
os.dirinstall: syscall.dirinstall once.install
|
||||
regexp.dirinstall: os.dirinstall
|
||||
reflect.dirinstall: strconv.dirinstall sync.dirinstall
|
||||
strconv.dirinstall: math.dirinstall os.dirinstall utf8.install
|
||||
|
@ -4,74 +4,41 @@
|
||||
|
||||
// For one-time initialization that is not done during init.
|
||||
// Wrap the initialization in a niladic function f() and call
|
||||
// once.Do(&f)
|
||||
// If multiple processes call once.Do(&f) simultaneously
|
||||
// once.Do(f)
|
||||
// If multiple processes call once.Do(f) simultaneously
|
||||
// with the same f argument, only one will call f, and the
|
||||
// others will block until f finishes running.
|
||||
|
||||
package once
|
||||
|
||||
type _Job struct {
|
||||
import "sync"
|
||||
|
||||
type job struct {
|
||||
done bool;
|
||||
doit chan bool; // buffer of 1
|
||||
sync.Mutex; // should probably be sync.Notification or some such
|
||||
}
|
||||
|
||||
type _Request struct {
|
||||
f func();
|
||||
reply chan *_Job
|
||||
}
|
||||
|
||||
var service = make(chan _Request)
|
||||
var jobmap = make(map[func()]*_Job)
|
||||
|
||||
// Moderate access to the jobmap.
|
||||
// Even if accesses were thread-safe (they should be but are not)
|
||||
// something needs to serialize creation of new jobs.
|
||||
// That's what the Server does.
|
||||
func server() {
|
||||
for {
|
||||
req := <-service;
|
||||
job, present := jobmap[req.f];
|
||||
if !present {
|
||||
job = new(_Job);
|
||||
job.doit = make(chan bool, 1);
|
||||
job.doit <- true;
|
||||
jobmap[req.f] = job
|
||||
}
|
||||
req.reply <- job
|
||||
}
|
||||
}
|
||||
var jobs = make(map[func()]*job)
|
||||
var joblock sync.Mutex;
|
||||
|
||||
func Do(f func()) {
|
||||
// Look for job in map (avoids channel communication).
|
||||
// If not there, ask map server to make one.
|
||||
// TODO: Uncomment use of jobmap[f] once
|
||||
// maps are thread-safe.
|
||||
var job *_Job;
|
||||
var present bool;
|
||||
// job, present = jobmap[f]
|
||||
joblock.Lock();
|
||||
j, present := jobs[f];
|
||||
if !present {
|
||||
c := make(chan *_Job);
|
||||
service <- _Request(f, c);
|
||||
job = <-c
|
||||
}
|
||||
|
||||
// Optimization
|
||||
if job.done {
|
||||
return
|
||||
}
|
||||
|
||||
// If we're the first one, job.doit has a true waiting.
|
||||
if <-job.doit {
|
||||
// run it
|
||||
j = new(job);
|
||||
j.Lock();
|
||||
jobs[f] = j;
|
||||
joblock.Unlock();
|
||||
f();
|
||||
job.done = true
|
||||
j.done = true;
|
||||
j.Unlock();
|
||||
} else {
|
||||
// wait for it
|
||||
joblock.Unlock();
|
||||
if j.done != true {
|
||||
j.Lock();
|
||||
j.Unlock();
|
||||
}
|
||||
|
||||
// Leave a false waiting for the next guy.
|
||||
job.doit <- false
|
||||
}
|
||||
|
||||
func init() {
|
||||
go server()
|
||||
}
|
||||
|
||||
|
@ -3,25 +3,71 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Environment variables.
|
||||
// Setenv doesn't exist yet: don't have the run-time hooks yet
|
||||
|
||||
package os
|
||||
|
||||
import os "os"
|
||||
import (
|
||||
"once";
|
||||
"os";
|
||||
)
|
||||
|
||||
var (
|
||||
ENOENV = NewError("no such environment variable");
|
||||
|
||||
env map[string] string;
|
||||
)
|
||||
|
||||
func Getenv(s string) (v string, err *Error) {
|
||||
n := len(s);
|
||||
if n == 0 {
|
||||
return "", EINVAL
|
||||
}
|
||||
for i, e := range sys.Envs {
|
||||
if len(e) > n && e[n] == '=' && e[0:n] == s {
|
||||
return e[n+1:len(e)], nil
|
||||
func copyenv() {
|
||||
env = make(map[string] string);
|
||||
for i, s := range sys.Envs {
|
||||
for j := 0; j < len(s); j++ {
|
||||
if s[j] == '=' {
|
||||
env[s[0:j]] = s[j+1:len(s)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "", ENOENV
|
||||
}
|
||||
}
|
||||
|
||||
func Getenv(key string) (value string, err *Error) {
|
||||
once.Do(copyenv);
|
||||
|
||||
if len(key) == 0 {
|
||||
return "", EINVAL;
|
||||
}
|
||||
v, ok := env[key];
|
||||
if !ok {
|
||||
return "", ENOENV;
|
||||
}
|
||||
return v, nil;
|
||||
}
|
||||
|
||||
func Setenv(key, value string) *Error {
|
||||
once.Do(copyenv);
|
||||
|
||||
if len(key) == 0 {
|
||||
return EINVAL;
|
||||
}
|
||||
env[key] = value;
|
||||
return nil;
|
||||
}
|
||||
|
||||
func Clearenv() {
|
||||
once.Do(copyenv); // prevent copyenv in Getenv/Setenv
|
||||
env = make(map[string] string);
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
once.Do(copyenv);
|
||||
a := make([]string, len(env));
|
||||
i := 0;
|
||||
for k, v := range(env) {
|
||||
// check i < len(a) for safety,
|
||||
// in case env is changing underfoot.
|
||||
if i < len(a) {
|
||||
a[i] = k + "=" + v;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return a[0:i];
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ func ForkExec(argv0 string, argv []string, envv []string, fd []*FD)
|
||||
}
|
||||
|
||||
func Exec(argv0 string, argv []string, envv []string) *Error {
|
||||
if envv == nil {
|
||||
envv = Environ();
|
||||
}
|
||||
e := syscall.Exec(argv0, argv, envv);
|
||||
return ErrnoToError(e);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ print <<EOF;
|
||||
|
||||
package syscall
|
||||
|
||||
export const (
|
||||
const (
|
||||
EOF
|
||||
|
||||
while(<>){
|
||||
|
@ -11,7 +11,7 @@ print <<EOF;
|
||||
|
||||
package syscall
|
||||
|
||||
export const(
|
||||
const(
|
||||
EOF
|
||||
|
||||
while(<>){
|
||||
@ -25,4 +25,7 @@ while(<>){
|
||||
|
||||
print <<EOF;
|
||||
)
|
||||
|
||||
func _darwin_system_call_conflict() {
|
||||
}
|
||||
EOF
|
||||
|
@ -10,7 +10,7 @@ print <<EOF;
|
||||
|
||||
package syscall
|
||||
|
||||
export const(
|
||||
const(
|
||||
EOF
|
||||
|
||||
while(<>){
|
||||
|
@ -138,7 +138,7 @@ func SecondsToUTC(sec int64) *Time {
|
||||
}
|
||||
t.Month = m+1;
|
||||
t.Day = yday+1;
|
||||
t.Zone = "GMT";
|
||||
t.Zone = "UTC";
|
||||
|
||||
return t;
|
||||
}
|
||||
@ -149,12 +149,12 @@ func UTC() *Time {
|
||||
|
||||
// TODO: Should this return an error?
|
||||
func SecondsToLocalTime(sec int64) *Time {
|
||||
zone, offset, err := time.LookupTimezone(sec);
|
||||
z, offset, err := time.LookupTimezone(sec);
|
||||
if err != nil {
|
||||
return SecondsToUTC(sec)
|
||||
}
|
||||
t := SecondsToUTC(sec+int64(offset));
|
||||
t.Zone = zone;
|
||||
t.Zone = z;
|
||||
t.ZoneOffset = offset;
|
||||
return t
|
||||
}
|
||||
|
@ -5,31 +5,39 @@
|
||||
package time
|
||||
|
||||
import (
|
||||
"os";
|
||||
"testing";
|
||||
"time";
|
||||
)
|
||||
|
||||
type _TimeTest struct {
|
||||
func init() {
|
||||
// Force US Pacific time for daylight-savings
|
||||
// tests below (localtests). Needs to be set
|
||||
// before the first call into the time library.
|
||||
os.Setenv("TZ", "US/Pacific");
|
||||
}
|
||||
|
||||
type TimeTest struct {
|
||||
seconds int64;
|
||||
golden Time;
|
||||
}
|
||||
|
||||
var utctests = []_TimeTest (
|
||||
_TimeTest(0, Time(1970, 1, 1, 0, 0, 0, Thursday, 0, "GMT")),
|
||||
_TimeTest(1221681866, Time(2008, 9, 17, 20, 4, 26, Wednesday, 0, "GMT")),
|
||||
_TimeTest(-1221681866, Time(1931, 4, 16, 3, 55, 34, Thursday, 0, "GMT")),
|
||||
_TimeTest(1e18, Time(31688740476, 10, 23, 1, 46, 40, Friday, 0, "GMT")),
|
||||
_TimeTest(-1e18, Time(-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "GMT")),
|
||||
_TimeTest(0x7fffffffffffffff, Time(292277026596, 12, 4, 15, 30, 7, Sunday, 0, "GMT")),
|
||||
_TimeTest(-0x8000000000000000, Time(-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "GMT"))
|
||||
var utctests = []TimeTest (
|
||||
TimeTest(0, Time(1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC")),
|
||||
TimeTest(1221681866, Time(2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC")),
|
||||
TimeTest(-1221681866, Time(1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC")),
|
||||
TimeTest(1e18, Time(31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC")),
|
||||
TimeTest(-1e18, Time(-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC")),
|
||||
TimeTest(0x7fffffffffffffff, Time(292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC")),
|
||||
TimeTest(-0x8000000000000000, Time(-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"))
|
||||
)
|
||||
|
||||
var localtests = []_TimeTest (
|
||||
_TimeTest(0, Time(1969, 12, 31, 16, 0, 0, Wednesday, -8*60*60, "PST")),
|
||||
_TimeTest(1221681866, Time(2008, 9, 17, 13, 4, 26, Wednesday, -7*60*60, "PDT"))
|
||||
var localtests = []TimeTest (
|
||||
TimeTest(0, Time(1969, 12, 31, 16, 0, 0, Wednesday, -8*60*60, "PST")),
|
||||
TimeTest(1221681866, Time(2008, 9, 17, 13, 4, 26, Wednesday, -7*60*60, "PDT"))
|
||||
)
|
||||
|
||||
func _Same(t, u *Time) bool {
|
||||
func same(t, u *Time) bool {
|
||||
return t.Year == u.Year
|
||||
&& t.Month == u.Month
|
||||
&& t.Day == u.Day
|
||||
@ -50,7 +58,7 @@ func TestSecondsToUTC(t *testing.T) {
|
||||
if newsec != sec {
|
||||
t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec);
|
||||
}
|
||||
if !_Same(tm, golden) {
|
||||
if !same(tm, golden) {
|
||||
t.Errorf("SecondsToUTC(%d):", sec);
|
||||
t.Errorf(" want=%v", *golden);
|
||||
t.Errorf(" have=%v", *tm);
|
||||
@ -67,7 +75,7 @@ func TestSecondsToLocalTime(t *testing.T) {
|
||||
if newsec != sec {
|
||||
t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec);
|
||||
}
|
||||
if !_Same(tm, golden) {
|
||||
if !same(tm, golden) {
|
||||
t.Errorf("SecondsToLocalTime(%d):", sec);
|
||||
t.Errorf(" want=%v", *golden);
|
||||
t.Errorf(" have=%v", *tm);
|
||||
|
@ -16,8 +16,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
_MaxFileSize = 8192; // actual files are closer to 1K
|
||||
_HeaderSize = 4+16+4*7
|
||||
maxFileSize = 8192; // actual files are closer to 1K
|
||||
headerSize = 4+16+4*7;
|
||||
|
||||
zoneDir = "/usr/share/zoneinfo/";
|
||||
)
|
||||
|
||||
var (
|
||||
@ -26,13 +28,13 @@ var (
|
||||
)
|
||||
|
||||
// Simple I/O interface to binary blob of data.
|
||||
type _Data struct {
|
||||
type data struct {
|
||||
p []byte;
|
||||
error bool;
|
||||
}
|
||||
|
||||
|
||||
func (d *_Data) Read(n int) []byte {
|
||||
func (d *data) read(n int) []byte {
|
||||
if len(d.p) < n {
|
||||
d.p = nil;
|
||||
d.error = true;
|
||||
@ -43,8 +45,8 @@ func (d *_Data) Read(n int) []byte {
|
||||
return p
|
||||
}
|
||||
|
||||
func (d *_Data) Big4() (n uint32, ok bool) {
|
||||
p := d.Read(4);
|
||||
func (d *data) big4() (n uint32, ok bool) {
|
||||
p := d.read(4);
|
||||
if len(p) < 4 {
|
||||
d.error = true;
|
||||
return 0, false
|
||||
@ -52,8 +54,8 @@ func (d *_Data) Big4() (n uint32, ok bool) {
|
||||
return uint32(p[0]) << 24 | uint32(p[1]) << 16 | uint32(p[2]) << 8 | uint32(p[3]), true
|
||||
}
|
||||
|
||||
func (d *_Data) Byte() (n byte, ok bool) {
|
||||
p := d.Read(1);
|
||||
func (d *data) byte() (n byte, ok bool) {
|
||||
p := d.read(1);
|
||||
if len(p) < 1 {
|
||||
d.error = true;
|
||||
return 0, false
|
||||
@ -63,7 +65,7 @@ func (d *_Data) Byte() (n byte, ok bool) {
|
||||
|
||||
|
||||
// Make a string by stopping at the first NUL
|
||||
func _ByteString(p []byte) string {
|
||||
func byteString(p []byte) string {
|
||||
for i := 0; i < len(p); i++ {
|
||||
if p[i] == 0 {
|
||||
return string(p[0:i])
|
||||
@ -73,31 +75,29 @@ func _ByteString(p []byte) string {
|
||||
}
|
||||
|
||||
// Parsed representation
|
||||
type _Zone struct {
|
||||
type zone struct {
|
||||
utcoff int;
|
||||
isdst bool;
|
||||
name string;
|
||||
}
|
||||
|
||||
type _Zonetime struct {
|
||||
type zonetime struct {
|
||||
time int32; // transition time, in seconds since 1970 GMT
|
||||
zone *_Zone; // the zone that goes into effect at that time
|
||||
zone *zone; // the zone that goes into effect at that time
|
||||
isstd, isutc bool; // ignored - no idea what these mean
|
||||
}
|
||||
|
||||
func parseinfo(bytes []byte) (zt []_Zonetime, err *os.Error) {
|
||||
|
||||
data1 := _Data(bytes, false);
|
||||
data := &data1;
|
||||
func parseinfo(bytes []byte) (zt []zonetime, err *os.Error) {
|
||||
d := data(bytes, false);
|
||||
|
||||
// 4-byte magic "TZif"
|
||||
if magic := data.Read(4); string(magic) != "TZif" {
|
||||
if magic := d.read(4); string(magic) != "TZif" {
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
|
||||
// 1-byte version, then 15 bytes of padding
|
||||
var p []byte;
|
||||
if p = data.Read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
|
||||
if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
vers := p[0];
|
||||
@ -119,7 +119,7 @@ func parseinfo(bytes []byte) (zt []_Zonetime, err *os.Error) {
|
||||
)
|
||||
var n [6]int;
|
||||
for i := 0; i < 6; i++ {
|
||||
nn, ok := data.Big4();
|
||||
nn, ok := d.big4();
|
||||
if !ok {
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
@ -127,32 +127,29 @@ func parseinfo(bytes []byte) (zt []_Zonetime, err *os.Error) {
|
||||
}
|
||||
|
||||
// Transition times.
|
||||
txtimes1 := _Data(data.Read(n[NTime]*4), false);
|
||||
txtimes := &txtimes1;
|
||||
txtimes := data(d.read(n[NTime]*4), false);
|
||||
|
||||
// Time zone indices for transition times.
|
||||
txzones := data.Read(n[NTime]);
|
||||
txzones := d.read(n[NTime]);
|
||||
|
||||
// Zone info structures
|
||||
zonedata1 := _Data(data.Read(n[NZone]*6), false);
|
||||
zonedata := &zonedata1;
|
||||
zonedata := data(d.read(n[NZone]*6), false);
|
||||
|
||||
// Time zone abbreviations.
|
||||
abbrev := data.Read(n[NChar]);
|
||||
abbrev := d.read(n[NChar]);
|
||||
|
||||
// Leap-second time pairs
|
||||
leapdata1 := _Data(data.Read(n[NLeap]*8), false);
|
||||
leapdata := &leapdata1;
|
||||
leapdata := data(d.read(n[NLeap]*8), false);
|
||||
|
||||
// Whether tx times associated with local time types
|
||||
// are specified as standard time or wall time.
|
||||
isstd := data.Read(n[NStdWall]);
|
||||
isstd := d.read(n[NStdWall]);
|
||||
|
||||
// Whether tx times associated with local time types
|
||||
// are specified as UTC or local time.
|
||||
isutc := data.Read(n[NUTCLocal]);
|
||||
isutc := d.read(n[NUTCLocal]);
|
||||
|
||||
if data.error { // ran out of data
|
||||
if d.error { // ran out of data
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
|
||||
@ -163,38 +160,38 @@ func parseinfo(bytes []byte) (zt []_Zonetime, err *os.Error) {
|
||||
// Now we can build up a useful data structure.
|
||||
// First the zone information.
|
||||
// utcoff[4] isdst[1] nameindex[1]
|
||||
zone := make([]_Zone, n[NZone]);
|
||||
for i := 0; i < len(zone); i++ {
|
||||
z := make([]zone, n[NZone]);
|
||||
for i := 0; i < len(z); i++ {
|
||||
var ok bool;
|
||||
var n uint32;
|
||||
if n, ok = zonedata.Big4(); !ok {
|
||||
if n, ok = zonedata.big4(); !ok {
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
zone[i].utcoff = int(n);
|
||||
z[i].utcoff = int(n);
|
||||
var b byte;
|
||||
if b, ok = zonedata.Byte(); !ok {
|
||||
if b, ok = zonedata.byte(); !ok {
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
zone[i].isdst = b != 0;
|
||||
if b, ok = zonedata.Byte(); !ok || int(b) >= len(abbrev) {
|
||||
z[i].isdst = b != 0;
|
||||
if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
zone[i].name = _ByteString(abbrev[b:len(abbrev)])
|
||||
z[i].name = byteString(abbrev[b:len(abbrev)])
|
||||
}
|
||||
|
||||
// Now the transition time info.
|
||||
zt = make([]_Zonetime, n[NTime]);
|
||||
zt = make([]zonetime, n[NTime]);
|
||||
for i := 0; i < len(zt); i++ {
|
||||
var ok bool;
|
||||
var n uint32;
|
||||
if n, ok = txtimes.Big4(); !ok {
|
||||
if n, ok = txtimes.big4(); !ok {
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
zt[i].time = int32(n);
|
||||
if int(txzones[i]) >= len(zone) {
|
||||
if int(txzones[i]) >= len(z) {
|
||||
return nil, BadZoneinfo
|
||||
}
|
||||
zt[i].zone = &zone[txzones[i]];
|
||||
zt[i].zone = &z[txzones[i]];
|
||||
if i < len(isstd) {
|
||||
zt[i].isstd = isstd[i] != 0
|
||||
}
|
||||
@ -208,52 +205,56 @@ func parseinfo(bytes []byte) (zt []_Zonetime, err *os.Error) {
|
||||
func readfile(name string, max int) (p []byte, err *os.Error) {
|
||||
fd, e := os.Open(name, os.O_RDONLY, 0);
|
||||
if e != nil {
|
||||
return nil, e
|
||||
return nil, e;
|
||||
}
|
||||
p = make([]byte, max+1)[0:0];
|
||||
n := 0;
|
||||
for len(p) < max {
|
||||
nn, e := fd.Read(p[n:cap(p)]);
|
||||
if e != nil {
|
||||
p = make([]byte, max);
|
||||
n, err1 := io.Readn(fd, p);
|
||||
fd.Close();
|
||||
return nil, e
|
||||
if err1 == nil { // too long
|
||||
return nil, BadZoneinfo;
|
||||
}
|
||||
if nn == 0 {
|
||||
fd.Close();
|
||||
return p, nil
|
||||
if err1 != io.ErrEOF {
|
||||
return nil, err1;
|
||||
}
|
||||
p = p[0:n+nn]
|
||||
}
|
||||
fd.Close();
|
||||
return nil, BadZoneinfo // too long
|
||||
return p[0:n], nil;
|
||||
}
|
||||
|
||||
|
||||
func readinfofile(name string) (tx []_Zonetime, err *os.Error) {
|
||||
data, e := readfile(name, _MaxFileSize);
|
||||
func readinfofile(name string) (tx []zonetime, err *os.Error) {
|
||||
buf, e := readfile(name, maxFileSize);
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
tx, err = parseinfo(data);
|
||||
tx, err = parseinfo(buf);
|
||||
return tx, err
|
||||
}
|
||||
|
||||
var zones []_Zonetime
|
||||
var zones []zonetime
|
||||
var zoneerr *os.Error
|
||||
|
||||
func _SetupZone() {
|
||||
// TODO: /etc/localtime is the default time zone info
|
||||
// for the system, but libc allows setting an environment
|
||||
// variable in order to direct reading a different file
|
||||
// (in /usr/share/zoneinfo). We should check that
|
||||
// environment variable.
|
||||
func setupZone() {
|
||||
// consult $TZ to find the time zone to use.
|
||||
// no $TZ means use the system default /etc/localtime.
|
||||
// $TZ="" means use UTC.
|
||||
// $TZ="foo" means use /usr/share/zoneinfo/foo.
|
||||
|
||||
tz, err := os.Getenv("TZ");
|
||||
var file string;
|
||||
switch {
|
||||
case err == os.ENOENV:
|
||||
zones, zoneerr = readinfofile("/etc/localtime");
|
||||
case err != nil:
|
||||
zoneerr = err;
|
||||
case len(tz) > 0:
|
||||
zones, zoneerr = readinfofile(zoneDir + tz);
|
||||
case len(tz) == 0:
|
||||
// do nothing: use UTC
|
||||
}
|
||||
}
|
||||
|
||||
func LookupTimezone(sec int64) (zone string, offset int, err *os.Error) {
|
||||
once.Do(_SetupZone);
|
||||
once.Do(setupZone);
|
||||
if zoneerr != nil || len(zones) == 0 {
|
||||
return "GMT", 0, zoneerr
|
||||
return "UTC", 0, zoneerr
|
||||
}
|
||||
|
||||
// Binary search for entry with largest time <= sec
|
||||
|
Loading…
Reference in New Issue
Block a user