@@ -500,44 +500,74 @@ fn print_c_errno() {
500
500
}
501
501
502
502
// get_raw_line returns a one-line string from stdin along with '\n' if there is any.
503
+ @[manualfree]
503
504
pub fn get_raw_line () string {
504
505
$if windows {
506
+ is_console := is_atty (0 ) > 0
507
+ wide_char_size := if is_console { 2 } else { 1 }
508
+ h_input := C.GetStdHandle (C.STD_INPUT_HANDLE)
509
+ if h_input == C.INVALID_HANDLE_VALUE {
510
+ return ''
511
+ }
505
512
unsafe {
506
- max_line_chars := 256
507
- mut old_size := max_line_chars * 2
508
- mut buf := malloc_noscan (old_size)
509
- h_input := C.GetStdHandle (C.STD_INPUT_HANDLE)
510
- mut bytes_read := u32 (0 )
511
- if is_atty (0 ) > 0 {
512
- x := C.ReadConsole (h_input, buf, max_line_chars * 2 , voidptr (& bytes_read),
513
- 0 )
514
- if ! x {
515
- return tos (buf, 0 )
516
- }
517
- return string_from_wide2 (& u16 (buf), int (bytes_read))
518
- }
513
+ initial_size := 256 * wide_char_size
514
+ mut buf := malloc_noscan (initial_size)
515
+ defer { buf.free () }
516
+ mut capacity := initial_size
519
517
mut offset := 0
518
+
520
519
for {
520
+ required_space := offset + wide_char_size
521
+ if required_space > capacity {
522
+ new_capacity := capacity * 2
523
+ new_buf := realloc_data (buf, capacity, new_capacity)
524
+ if new_buf == 0 {
525
+ break
526
+ }
527
+ buf = new_buf
528
+ capacity = new_capacity
529
+ }
530
+
521
531
pos := buf + offset
522
- res := C.ReadFile (h_input, pos, 1 , voidptr (& bytes_read), 0 )
523
- if ! res && offset == 0 {
524
- return tos (buf, 0 )
532
+ mut bytes_read := u32 (0 )
533
+ res := if is_console {
534
+ C.ReadConsole (h_input, pos, 1 , voidptr (& bytes_read), 0 )
535
+ } else {
536
+ C.ReadFile (h_input, pos, 1 , voidptr (& bytes_read), 0 )
525
537
}
538
+
526
539
if ! res || bytes_read == 0 {
527
540
break
528
541
}
529
- if * pos == `\n ` {
530
- offset++
531
- break
532
- }
533
- offset++
534
- if offset > = old_size {
535
- new_size := old_size + max_line_chars * 2
536
- buf = realloc_data (buf, old_size, new_size)
537
- old_size = new_size
542
+
543
+ // check for `\n` and Ctrl+Z
544
+ if is_console {
545
+ read_char := * (& u16 (pos))
546
+ if read_char == `\n ` {
547
+ offset + = wide_char_size
548
+ break
549
+ } else if read_char == 0x1A {
550
+ break
551
+ }
552
+ } else {
553
+ read_byte := * pos
554
+ if read_byte == `\n ` {
555
+ offset + = wide_char_size
556
+ break
557
+ } else if read_byte == 0x1A {
558
+ break
559
+ }
538
560
}
561
+
562
+ offset + = wide_char_size
563
+ }
564
+
565
+ return if is_console {
566
+ string_from_wide2 (& u16 (buf), offset / 2 )
567
+ } else {
568
+ // let defer buf.free() to avoid memory leak
569
+ buf.vstring_with_len (offset).clone ()
539
570
}
540
- return buf.vstring_with_len (offset)
541
571
}
542
572
} $else {
543
573
max := usize (0 )
0 commit comments