8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ // FIXME #3921. This is unsafe because linenoise uses global mutable
12
+ // state without mutexes.
13
+
11
14
use std:: c_str:: ToCStr ;
12
15
use std:: libc:: { c_char, c_int} ;
13
- use std:: { local_data, str , rt } ;
14
- use std:: unstable :: finally :: Finally ;
16
+ use std:: local_data;
17
+ use std:: str ;
15
18
16
19
#[ cfg( stage0) ]
17
20
pub mod rustrt {
@@ -25,9 +28,6 @@ pub mod rustrt {
25
28
fn linenoiseHistoryLoad ( file : * c_char ) -> c_int ;
26
29
fn linenoiseSetCompletionCallback ( callback : * u8 ) ;
27
30
fn linenoiseAddCompletion ( completions : * ( ) , line : * c_char ) ;
28
-
29
- fn rust_take_linenoise_lock ( ) ;
30
- fn rust_drop_linenoise_lock ( ) ;
31
31
}
32
32
}
33
33
@@ -42,107 +42,65 @@ pub mod rustrt {
42
42
externfn ! ( fn linenoiseHistoryLoad( file: * c_char) -> c_int)
43
43
externfn ! ( fn linenoiseSetCompletionCallback( callback: extern "C" fn ( * i8 , * ( ) ) ) )
44
44
externfn ! ( fn linenoiseAddCompletion( completions: * ( ) , line: * c_char) )
45
-
46
- externfn ! ( fn rust_take_linenoise_lock( ) )
47
- externfn ! ( fn rust_drop_linenoise_lock( ) )
48
- }
49
-
50
- macro_rules! locked {
51
- ( $expr: expr) => {
52
- unsafe {
53
- // FIXME #9105: can't use a static mutex in pure Rust yet.
54
- rustrt:: rust_take_linenoise_lock( ) ;
55
- let x = $expr;
56
- rustrt:: rust_drop_linenoise_lock( ) ;
57
- x
58
- }
59
- }
60
45
}
61
46
62
47
/// Add a line to history
63
- pub fn add_history ( line : & str ) -> bool {
48
+ pub unsafe fn add_history ( line : & str ) -> bool {
64
49
do line. with_c_str |buf| {
65
- ( locked ! ( rustrt:: linenoiseHistoryAdd( buf) ) ) == 1 as c_int
50
+ rustrt:: linenoiseHistoryAdd ( buf) == 1 as c_int
66
51
}
67
52
}
68
53
69
54
/// Set the maximum amount of lines stored
70
- pub fn set_history_max_len ( len : int ) -> bool {
71
- ( locked ! ( rustrt:: linenoiseHistorySetMaxLen( len as c_int) ) ) == 1 as c_int
55
+ pub unsafe fn set_history_max_len ( len : int ) -> bool {
56
+ rustrt:: linenoiseHistorySetMaxLen ( len as c_int ) == 1 as c_int
72
57
}
73
58
74
59
/// Save line history to a file
75
- pub fn save_history ( file : & str ) -> bool {
60
+ pub unsafe fn save_history ( file : & str ) -> bool {
76
61
do file. with_c_str |buf| {
77
- // 0 on success, -1 on failure
78
- ( locked ! ( rustrt:: linenoiseHistorySave( buf) ) ) == 0 as c_int
62
+ rustrt:: linenoiseHistorySave ( buf) == 1 as c_int
79
63
}
80
64
}
81
65
82
66
/// Load line history from a file
83
- pub fn load_history ( file : & str ) -> bool {
67
+ pub unsafe fn load_history ( file : & str ) -> bool {
84
68
do file. with_c_str |buf| {
85
- // 0 on success, -1 on failure
86
- ( locked ! ( rustrt:: linenoiseHistoryLoad( buf) ) ) == 0 as c_int
69
+ rustrt:: linenoiseHistoryLoad ( buf) == 1 as c_int
87
70
}
88
71
}
89
72
90
73
/// Print out a prompt and then wait for input and return it
91
- pub fn read ( prompt : & str ) -> Option < ~str > {
74
+ pub unsafe fn read ( prompt : & str ) -> Option < ~str > {
92
75
do prompt. with_c_str |buf| {
93
- let line = locked ! ( rustrt:: linenoise( buf) ) ;
76
+ let line = rustrt:: linenoise ( buf) ;
94
77
95
78
if line. is_null ( ) { None }
96
- else {
97
- unsafe {
98
- do ( || {
99
- Some ( str:: raw:: from_c_str ( line) )
100
- } ) . finally {
101
- // linenoise's return value is from strdup, so we
102
- // better not leak it.
103
- rt:: global_heap:: exchange_free ( line) ;
104
- }
105
- }
106
- }
79
+ else { Some ( str:: raw:: from_c_str ( line) ) }
107
80
}
108
81
}
109
82
110
83
pub type CompletionCb = @fn ( ~str , @fn ( ~str ) ) ;
111
84
112
- static complete_key: local_data:: Key < CompletionCb > = & local_data:: Key ;
113
-
114
- /// Bind to the main completion callback in the current task.
115
- ///
116
- /// The completion callback should not call any `extra::rl` functions
117
- /// other than the closure that it receives as its second
118
- /// argument. Calling such a function will deadlock on the mutex used
119
- /// to ensure that the calls are thread-safe.
120
- pub fn complete ( cb : CompletionCb ) {
121
- local_data:: set ( complete_key, cb) ;
122
-
123
- extern fn callback ( c_line : * c_char , completions : * ( ) ) {
124
- do local_data:: get ( complete_key) |opt_cb| {
125
- // only fetch completions if a completion handler has been
126
- // registered in the current task.
127
- match opt_cb {
128
- None => { } ,
129
- Some ( cb) => {
130
- let line = unsafe { str:: raw:: from_c_str ( c_line) } ;
131
- do ( * cb) ( line) |suggestion| {
132
- do suggestion. with_c_str |buf| {
133
- // This isn't locked, because `callback` gets
134
- // called inside `rustrt::linenoise`, which
135
- // *is* already inside the mutex, so
136
- // re-locking would be a deadlock.
137
- unsafe {
138
- rustrt:: linenoiseAddCompletion ( completions, buf) ;
139
- }
140
- }
85
+ static complete_key: local_data:: Key < @CompletionCb > = & local_data:: Key ;
86
+
87
+ /// Bind to the main completion callback
88
+ pub unsafe fn complete ( cb : CompletionCb ) {
89
+ local_data:: set ( complete_key, @cb) ;
90
+
91
+ extern fn callback ( line : * c_char , completions : * ( ) ) {
92
+ do local_data:: get ( complete_key) |cb| {
93
+ let cb = * * cb. unwrap ( ) ;
94
+
95
+ unsafe {
96
+ do cb ( str:: raw:: from_c_str ( line) ) |suggestion| {
97
+ do suggestion. with_c_str |buf| {
98
+ rustrt:: linenoiseAddCompletion ( completions, buf) ;
141
99
}
142
100
}
143
101
}
144
102
}
145
103
}
146
104
147
- locked ! ( rustrt:: linenoiseSetCompletionCallback( callback) ) ;
105
+ rustrt:: linenoiseSetCompletionCallback ( callback) ;
148
106
}
0 commit comments