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" |
(...skipping 14 matching lines...) Expand all Loading... |
25 // to close the wrong file descriptor. | 25 // to close the wrong file descriptor. |
26 type file struct { | 26 type file struct { |
27 fd syscall.Handle | 27 fd syscall.Handle |
28 name string | 28 name string |
29 dirinfo *dirInfo // nil unless directory being read | 29 dirinfo *dirInfo // nil unless directory being read |
30 l sync.Mutex // used to implement windows pread/pwrite | 30 l sync.Mutex // used to implement windows pread/pwrite |
31 | 31 |
32 // only for console io | 32 // only for console io |
33 isConsole bool | 33 isConsole bool |
34 lastbits []byte // first few bytes of the last incomplete rune in last
write | 34 lastbits []byte // first few bytes of the last incomplete rune in last
write |
35 » readbuf []rune // input console buffer | 35 » conInLine string // console input line buffer |
36 } | 36 } |
37 | 37 |
38 // Fd returns the Windows handle referencing the open file. | 38 // Fd returns the Windows handle referencing the open file. |
39 func (file *File) Fd() uintptr { | 39 func (file *File) Fd() uintptr { |
40 if file == nil { | 40 if file == nil { |
41 return uintptr(syscall.InvalidHandle) | 41 return uintptr(syscall.InvalidHandle) |
42 } | 42 } |
43 return uintptr(file.fd) | 43 return uintptr(file.fd) |
44 } | 44 } |
45 | 45 |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 } | 238 } |
239 n-- | 239 n-- |
240 fi = append(fi, f) | 240 fi = append(fi, f) |
241 } | 241 } |
242 if !wantAll && len(fi) == 0 { | 242 if !wantAll && len(fi) == 0 { |
243 return fi, io.EOF | 243 return fi, io.EOF |
244 } | 244 } |
245 return fi, nil | 245 return fi, nil |
246 } | 246 } |
247 | 247 |
| 248 const conEOT = 0x1A // For a Windows console, Control-Z is EOT |
| 249 |
| 250 // readConsoleLine reads a line of character input from the Windows console inpu
t buffer. |
| 251 // Control-Z interrupts and Enter interrupts and ends input for a line. |
| 252 // Enter ("\r\n") is returned as "\n". |
| 253 func (f *File) readConsoleLine() (err error) { |
| 254 if f == nil { |
| 255 return ErrInvalid |
| 256 } |
| 257 f.conInLine = "" |
| 258 |
| 259 var mode uint32 |
| 260 err = syscall.GetConsoleMode(f.fd, &mode) |
| 261 if err != nil { |
| 262 return err |
| 263 } |
| 264 const plMode = syscall.ENABLE_PROCESSED_INPUT | syscall.ENABLE_LINE_INPU
T |
| 265 if mode&plMode != plMode { |
| 266 defer func(mode uint32) { |
| 267 e := syscall.SetConsoleMode(f.fd, mode) |
| 268 if e != nil { |
| 269 err = e |
| 270 f.conInLine = "" |
| 271 } |
| 272 }(mode) |
| 273 err = syscall.SetConsoleMode(f.fd, mode|plMode) |
| 274 if err != nil { |
| 275 return err |
| 276 } |
| 277 } |
| 278 |
| 279 var rLine []rune |
| 280 const bufLen = 256 - 1 |
| 281 buf := make([]uint16, bufLen, bufLen+1) |
| 282 var nr uint32 |
| 283 // Note: CONSOLE_READCONSOLE_CONTROL structure |
| 284 // Minimum support: Windows Vista or Windows Server 2008 [desktop apps o
nly]. |
| 285 // If not available, Control-Z is buffered until Enter is pressed. |
| 286 crc := syscall.ConsoleReadconsoleControl{ |
| 287 Length: 4 * 4, |
| 288 CtrlWakeupMask: 1 << conEOT, |
| 289 } |
| 290 for { |
| 291 // Unicode: ReadConsoleW |
| 292 err := syscall.ReadConsole(f.fd, &buf[0], uint32(bufLen), &nr, &
crc) |
| 293 if err != nil { |
| 294 return err |
| 295 } |
| 296 rBuf := utf16.Decode(buf[:nr]) |
| 297 if len(rLine) == 0 { |
| 298 rLine = rBuf |
| 299 } else { |
| 300 rLine = append(rLine, rBuf...) |
| 301 } |
| 302 if len(rLine) > 0 { |
| 303 end := len(rLine) - 1 |
| 304 if rLine[end] == conEOT { |
| 305 break |
| 306 } |
| 307 if rLine[end] == '\n' { |
| 308 if len(rLine) > 1 { |
| 309 if rLine[end-1] == '\r' { |
| 310 rLine[end-1] = rLine[end] |
| 311 rLine = rLine[:end] |
| 312 } |
| 313 } |
| 314 break |
| 315 } |
| 316 } |
| 317 } |
| 318 f.conInLine = string(rLine) |
| 319 return nil |
| 320 } |
| 321 |
248 // readConsole reads utf16 characters from console File, | 322 // readConsole reads utf16 characters from console File, |
249 // encodes them into utf8 and stores them in buffer b. | 323 // encodes them into utf8 and stores them in buffer b. |
250 // It returns the number of utf8 bytes read and an error, if any. | 324 // It returns the number of utf8 bytes read and an error, if any. |
| 325 // For os package portability, the buffer contents match those returned under Li
nux, |
| 326 // except for OS dependent control characters and keys. |
| 327 // Control-Z on Windows is the equivalent to Control-D on Linux. |
| 328 // Enter ("\r\n") is returned as "\n". |
251 func (f *File) readConsole(b []byte) (n int, err error) { | 329 func (f *File) readConsole(b []byte) (n int, err error) { |
252 » if len(b) == 0 { | 330 » if f == nil { |
253 » » return 0, nil | 331 » » return 0, ErrInvalid |
254 » } | 332 » } |
255 » if len(f.readbuf) == 0 { | 333 » b = b[:0:len(b)] |
256 » » // syscall.ReadConsole seems to fail, if given large buffer. | 334 |
257 » » // So limit the buffer to 16000 characters. | 335 » if len(f.conInLine) == 0 { |
258 » » numBytes := len(b) | 336 » » err = f.readConsoleLine() |
259 » » if numBytes > 16000 { | |
260 » » » numBytes = 16000 | |
261 » » } | |
262 » » // get more input data from os | |
263 » » wchars := make([]uint16, numBytes) | |
264 » » var p *uint16 | |
265 » » if len(b) > 0 { | |
266 » » » p = &wchars[0] | |
267 » » } | |
268 » » var nw uint32 | |
269 » » err := syscall.ReadConsole(f.fd, p, uint32(len(wchars)), &nw, ni
l) | |
270 if err != nil { | 337 if err != nil { |
| 338 f.conInLine = "" |
271 return 0, err | 339 return 0, err |
272 } | 340 } |
273 » » f.readbuf = utf16.Decode(wchars[:nw]) | 341 » } |
274 » } | 342 |
275 » for i, r := range f.readbuf { | 343 » i := 0 |
276 » » if utf8.RuneLen(r) > len(b) { | 344 » for i < len(f.conInLine) { |
277 » » » f.readbuf = f.readbuf[i:] | 345 » » if f.conInLine[i] == conEOT { |
278 » » » return n, nil | 346 » » » if i == 0 { |
279 » » } | 347 » » » » f.conInLine = "" |
280 » » nr := utf8.EncodeRune(b, r) | 348 » » » » return 0, nil // io.EOF |
281 » » b = b[nr:] | 349 » » » } |
282 » » n += nr | 350 » » » i++ |
283 » } | 351 » » » if i < len(f.conInLine) && f.conInLine[i] == '\n' { |
284 » f.readbuf = nil | 352 » » » » i++ |
285 » return n, nil | 353 » » » } |
| 354 » » » break |
| 355 » » } |
| 356 » » if len(b)+1 > cap(b) { |
| 357 » » » break |
| 358 » » } |
| 359 » » b = b[:len(b)+1] |
| 360 » » b[len(b)-1] = f.conInLine[i] |
| 361 » » i++ |
| 362 » } |
| 363 » f.conInLine = f.conInLine[i:] |
| 364 » return len(b), nil |
286 } | 365 } |
287 | 366 |
288 // read reads up to len(b) bytes from the File. | 367 // read reads up to len(b) bytes from the File. |
289 // It returns the number of bytes read and an error, if any. | 368 // It returns the number of bytes read and an error, if any. |
290 func (f *File) read(b []byte) (n int, err error) { | 369 func (f *File) read(b []byte) (n int, err error) { |
291 f.l.Lock() | 370 f.l.Lock() |
292 defer f.l.Unlock() | 371 defer f.l.Unlock() |
293 if f.isConsole { | 372 if f.isConsole { |
294 return f.readConsole(b) | 373 return f.readConsole(b) |
295 } | 374 } |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0]) | 565 n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0]) |
487 if n > uint32(len(dirw)) { | 566 if n > uint32(len(dirw)) { |
488 n = 0 | 567 n = 0 |
489 } | 568 } |
490 } | 569 } |
491 if n > 0 && dirw[n-1] == pathSep { | 570 if n > 0 && dirw[n-1] == pathSep { |
492 n-- | 571 n-- |
493 } | 572 } |
494 return string(utf16.Decode(dirw[0:n])) | 573 return string(utf16.Decode(dirw[0:n])) |
495 } | 574 } |
LEFT | RIGHT |