LEFT | RIGHT |
(no file at all) | |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package os | 5 package os |
6 | 6 |
7 import ( | 7 import ( |
8 "io" | 8 "io" |
9 "runtime" | 9 "runtime" |
10 "sync" | 10 "sync" |
11 "syscall" | 11 "syscall" |
12 "unicode/utf16" | 12 "unicode/utf16" |
| 13 "unicode/utf8" |
13 ) | 14 ) |
14 | 15 |
15 // File represents an open file descriptor. | 16 // File represents an open file descriptor. |
16 type File struct { | 17 type File struct { |
17 *file | 18 *file |
18 } | 19 } |
19 | 20 |
20 // file is the real representation of *File. | 21 // file is the real representation of *File. |
21 // The extra level of indirection ensures that no clients of os | 22 // The extra level of indirection ensures that no clients of os |
22 // can overwrite this data, which could cause the finalizer | 23 // can overwrite this data, which could cause the finalizer |
23 // to close the wrong file descriptor. | 24 // to close the wrong file descriptor. |
24 type file struct { | 25 type file struct { |
25 fd syscall.Handle | 26 fd syscall.Handle |
26 name string | 27 name string |
27 dirinfo *dirInfo // nil unless directory being read | 28 dirinfo *dirInfo // nil unless directory being read |
28 l sync.Mutex // used to implement windows pread/pwrite | 29 l sync.Mutex // used to implement windows pread/pwrite |
| 30 |
| 31 // only for console io |
| 32 isConsole bool |
| 33 lastbits []byte // first few bytes of the last incomplete rune in last
write |
29 } | 34 } |
30 | 35 |
31 // Fd returns the Windows handle referencing the open file. | 36 // Fd returns the Windows handle referencing the open file. |
32 func (file *File) Fd() uintptr { | 37 func (file *File) Fd() uintptr { |
33 if file == nil { | 38 if file == nil { |
34 return uintptr(syscall.InvalidHandle) | 39 return uintptr(syscall.InvalidHandle) |
35 } | 40 } |
36 return uintptr(file.fd) | 41 return uintptr(file.fd) |
37 } | 42 } |
38 | 43 |
39 // NewFile returns a new File with the given file descriptor and name. | 44 // NewFile returns a new File with the given file descriptor and name. |
40 func NewFile(fd uintptr, name string) *File { | 45 func NewFile(fd uintptr, name string) *File { |
41 h := syscall.Handle(fd) | 46 h := syscall.Handle(fd) |
42 if h == syscall.InvalidHandle { | 47 if h == syscall.InvalidHandle { |
43 return nil | 48 return nil |
44 } | 49 } |
45 f := &File{&file{fd: h, name: name}} | 50 f := &File{&file{fd: h, name: name}} |
| 51 var m uint32 |
| 52 if syscall.GetConsoleMode(f.fd, &m) == nil { |
| 53 f.isConsole = true |
| 54 } |
46 runtime.SetFinalizer(f.file, (*file).close) | 55 runtime.SetFinalizer(f.file, (*file).close) |
47 return f | 56 return f |
48 } | 57 } |
49 | 58 |
50 // Auxiliary information if the File describes a directory | 59 // Auxiliary information if the File describes a directory |
51 type dirInfo struct { | 60 type dirInfo struct { |
52 data syscall.Win32finddata | 61 data syscall.Win32finddata |
53 needdata bool | 62 needdata bool |
54 path string | 63 path string |
55 } | 64 } |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 Offset: uint32(off), | 232 Offset: uint32(off), |
224 } | 233 } |
225 var done uint32 | 234 var done uint32 |
226 e = syscall.ReadFile(syscall.Handle(f.fd), b, &done, &o) | 235 e = syscall.ReadFile(syscall.Handle(f.fd), b, &done, &o) |
227 if e != nil { | 236 if e != nil { |
228 return 0, e | 237 return 0, e |
229 } | 238 } |
230 return int(done), nil | 239 return int(done), nil |
231 } | 240 } |
232 | 241 |
| 242 // writeConsole writes len(b) bytes to the console File. |
| 243 // It returns the number of bytes written and an error, if any. |
| 244 func (f *File) writeConsole(b []byte) (n int, err error) { |
| 245 n = len(b) |
| 246 runes := make([]rune, 0, 256) |
| 247 if len(f.lastbits) > 0 { |
| 248 b = append(f.lastbits, b...) |
| 249 f.lastbits = nil |
| 250 |
| 251 } |
| 252 for len(b) >= utf8.UTFMax || utf8.FullRune(b) { |
| 253 r, l := utf8.DecodeRune(b) |
| 254 runes = append(runes, r) |
| 255 b = b[l:] |
| 256 } |
| 257 if len(b) > 0 { |
| 258 f.lastbits = make([]byte, len(b)) |
| 259 copy(f.lastbits, b) |
| 260 } |
| 261 if len(runes) > 0 { |
| 262 uint16s := utf16.Encode(runes) |
| 263 for len(uint16s) > 0 { |
| 264 var written uint32 |
| 265 err = syscall.WriteConsole(f.fd, &uint16s[0], uint32(len
(uint16s)), &written, nil) |
| 266 if err != nil { |
| 267 return 0, nil |
| 268 } |
| 269 uint16s = uint16s[written:] |
| 270 } |
| 271 } |
| 272 return n, nil |
| 273 } |
| 274 |
233 // write writes len(b) bytes to the File. | 275 // write writes len(b) bytes to the File. |
234 // It returns the number of bytes written and an error, if any. | 276 // It returns the number of bytes written and an error, if any. |
235 func (f *File) write(b []byte) (n int, err error) { | 277 func (f *File) write(b []byte) (n int, err error) { |
236 f.l.Lock() | 278 f.l.Lock() |
237 defer f.l.Unlock() | 279 defer f.l.Unlock() |
| 280 if f.isConsole { |
| 281 return f.writeConsole(b) |
| 282 } |
238 return syscall.Write(f.fd, b) | 283 return syscall.Write(f.fd, b) |
239 } | 284 } |
240 | 285 |
241 // pwrite writes len(b) bytes to the File starting at byte offset off. | 286 // pwrite writes len(b) bytes to the File starting at byte offset off. |
242 // It returns the number of bytes written and an error, if any. | 287 // It returns the number of bytes written and an error, if any. |
243 func (f *File) pwrite(b []byte, off int64) (n int, err error) { | 288 func (f *File) pwrite(b []byte, off int64) (n int, err error) { |
244 f.l.Lock() | 289 f.l.Lock() |
245 defer f.l.Unlock() | 290 defer f.l.Unlock() |
246 curoffset, e := syscall.Seek(f.fd, 0, 1) | 291 curoffset, e := syscall.Seek(f.fd, 0, 1) |
247 if e != nil { | 292 if e != nil { |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0]) | 392 n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0]) |
348 if n > uint32(len(dirw)) { | 393 if n > uint32(len(dirw)) { |
349 n = 0 | 394 n = 0 |
350 } | 395 } |
351 } | 396 } |
352 if n > 0 && dirw[n-1] == pathSep { | 397 if n > 0 && dirw[n-1] == pathSep { |
353 n-- | 398 n-- |
354 } | 399 } |
355 return string(utf16.Decode(dirw[0:n])) | 400 return string(utf16.Decode(dirw[0:n])) |
356 } | 401 } |
LEFT | RIGHT |