- fix unused params - unconditionalize vis.hdiff -r1.27 -r1.28 src/lib/libedit/common.c
(christos)
--- src/lib/libedit/common.c 2011/07/29 15:20:39 1.27
+++ src/lib/libedit/common.c 2011/07/29 20:58:07 1.28
@@ -1,921 +1,922 @@ | @@ -1,921 +1,922 @@ | |||
1 | /* $NetBSD: common.c,v 1.27 2011/07/29 15:20:39 christos Exp $ */ | 1 | /* $NetBSD: common.c,v 1.28 2011/07/29 20:58:07 christos Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1992, 1993 | 4 | * Copyright (c) 1992, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Christos Zoulas of Cornell University. | 8 | * Christos Zoulas of Cornell University. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | #include "config.h" | 35 | #include "config.h" | |
36 | #if !defined(lint) && !defined(SCCSID) | 36 | #if !defined(lint) && !defined(SCCSID) | |
37 | #if 0 | 37 | #if 0 | |
38 | static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; | 38 | static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; | |
39 | #else | 39 | #else | |
40 | __RCSID("$NetBSD: common.c,v 1.27 2011/07/29 15:20:39 christos Exp $"); | 40 | __RCSID("$NetBSD: common.c,v 1.28 2011/07/29 20:58:07 christos Exp $"); | |
41 | #endif | 41 | #endif | |
42 | #endif /* not lint && not SCCSID */ | 42 | #endif /* not lint && not SCCSID */ | |
43 | 43 | |||
44 | /* | 44 | /* | |
45 | * common.c: Common Editor functions | 45 | * common.c: Common Editor functions | |
46 | */ | 46 | */ | |
47 | #include "el.h" | 47 | #include "el.h" | |
48 | 48 | |||
49 | /* ed_end_of_file(): | 49 | /* ed_end_of_file(): | |
50 | * Indicate end of file | 50 | * Indicate end of file | |
51 | * [^D] | 51 | * [^D] | |
52 | */ | 52 | */ | |
53 | protected el_action_t | 53 | protected el_action_t | |
54 | /*ARGSUSED*/ | 54 | /*ARGSUSED*/ | |
55 | ed_end_of_file(EditLine *el, Int c __attribute__((__unused__))) | 55 | ed_end_of_file(EditLine *el, Int c __attribute__((__unused__))) | |
56 | { | 56 | { | |
57 | 57 | |||
58 | re_goto_bottom(el); | 58 | re_goto_bottom(el); | |
59 | *el->el_line.lastchar = '\0'; | 59 | *el->el_line.lastchar = '\0'; | |
60 | return CC_EOF; | 60 | return CC_EOF; | |
61 | } | 61 | } | |
62 | 62 | |||
63 | 63 | |||
64 | /* ed_insert(): | 64 | /* ed_insert(): | |
65 | * Add character to the line | 65 | * Add character to the line | |
66 | * Insert a character [bound to all insert keys] | 66 | * Insert a character [bound to all insert keys] | |
67 | */ | 67 | */ | |
68 | protected el_action_t | 68 | protected el_action_t | |
69 | ed_insert(EditLine *el, Int c) | 69 | ed_insert(EditLine *el, Int c) | |
70 | { | 70 | { | |
71 | int count = el->el_state.argument; | 71 | int count = el->el_state.argument; | |
72 | 72 | |||
73 | if (c == '\0') | 73 | if (c == '\0') | |
74 | return CC_ERROR; | 74 | return CC_ERROR; | |
75 | 75 | |||
76 | if (el->el_line.lastchar + el->el_state.argument >= | 76 | if (el->el_line.lastchar + el->el_state.argument >= | |
77 | el->el_line.limit) { | 77 | el->el_line.limit) { | |
78 | /* end of buffer space, try to allocate more */ | 78 | /* end of buffer space, try to allocate more */ | |
79 | if (!ch_enlargebufs(el, (size_t) count)) | 79 | if (!ch_enlargebufs(el, (size_t) count)) | |
80 | return CC_ERROR; /* error allocating more */ | 80 | return CC_ERROR; /* error allocating more */ | |
81 | } | 81 | } | |
82 | 82 | |||
83 | if (count == 1) { | 83 | if (count == 1) { | |
84 | if (el->el_state.inputmode == MODE_INSERT | 84 | if (el->el_state.inputmode == MODE_INSERT | |
85 | || el->el_line.cursor >= el->el_line.lastchar) | 85 | || el->el_line.cursor >= el->el_line.lastchar) | |
86 | c_insert(el, 1); | 86 | c_insert(el, 1); | |
87 | 87 | |||
88 | *el->el_line.cursor++ = c; | 88 | *el->el_line.cursor++ = c; | |
89 | re_fastaddc(el); /* fast refresh for one char. */ | 89 | re_fastaddc(el); /* fast refresh for one char. */ | |
90 | } else { | 90 | } else { | |
91 | if (el->el_state.inputmode != MODE_REPLACE_1) | 91 | if (el->el_state.inputmode != MODE_REPLACE_1) | |
92 | c_insert(el, el->el_state.argument); | 92 | c_insert(el, el->el_state.argument); | |
93 | 93 | |||
94 | while (count-- && el->el_line.cursor < el->el_line.lastchar) | 94 | while (count-- && el->el_line.cursor < el->el_line.lastchar) | |
95 | *el->el_line.cursor++ = c; | 95 | *el->el_line.cursor++ = c; | |
96 | re_refresh(el); | 96 | re_refresh(el); | |
97 | } | 97 | } | |
98 | 98 | |||
99 | if (el->el_state.inputmode == MODE_REPLACE_1) | 99 | if (el->el_state.inputmode == MODE_REPLACE_1) | |
100 | return vi_command_mode(el, 0); | 100 | return vi_command_mode(el, 0); | |
101 | 101 | |||
102 | return CC_NORM; | 102 | return CC_NORM; | |
103 | } | 103 | } | |
104 | 104 | |||
105 | 105 | |||
106 | /* ed_delete_prev_word(): | 106 | /* ed_delete_prev_word(): | |
107 | * Delete from beginning of current word to cursor | 107 | * Delete from beginning of current word to cursor | |
108 | * [M-^?] [^W] | 108 | * [M-^?] [^W] | |
109 | */ | 109 | */ | |
110 | protected el_action_t | 110 | protected el_action_t | |
111 | /*ARGSUSED*/ | 111 | /*ARGSUSED*/ | |
112 | ed_delete_prev_word(EditLine *el, Int c __attribute__((__unused__))) | 112 | ed_delete_prev_word(EditLine *el, Int c __attribute__((__unused__))) | |
113 | { | 113 | { | |
114 | Char *cp, *p, *kp; | 114 | Char *cp, *p, *kp; | |
115 | 115 | |||
116 | if (el->el_line.cursor == el->el_line.buffer) | 116 | if (el->el_line.cursor == el->el_line.buffer) | |
117 | return CC_ERROR; | 117 | return CC_ERROR; | |
118 | 118 | |||
119 | cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, | 119 | cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, | |
120 | el->el_state.argument, ce__isword); | 120 | el->el_state.argument, ce__isword); | |
121 | 121 | |||
122 | for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++) | 122 | for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++) | |
123 | *kp++ = *p; | 123 | *kp++ = *p; | |
124 | el->el_chared.c_kill.last = kp; | 124 | el->el_chared.c_kill.last = kp; | |
125 | 125 | |||
126 | c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */ | 126 | c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */ | |
127 | el->el_line.cursor = cp; | 127 | el->el_line.cursor = cp; | |
128 | if (el->el_line.cursor < el->el_line.buffer) | 128 | if (el->el_line.cursor < el->el_line.buffer) | |
129 | el->el_line.cursor = el->el_line.buffer; /* bounds check */ | 129 | el->el_line.cursor = el->el_line.buffer; /* bounds check */ | |
130 | return CC_REFRESH; | 130 | return CC_REFRESH; | |
131 | } | 131 | } | |
132 | 132 | |||
133 | 133 | |||
134 | /* ed_delete_next_char(): | 134 | /* ed_delete_next_char(): | |
135 | * Delete character under cursor | 135 | * Delete character under cursor | |
136 | * [^D] [x] | 136 | * [^D] [x] | |
137 | */ | 137 | */ | |
138 | protected el_action_t | 138 | protected el_action_t | |
139 | /*ARGSUSED*/ | 139 | /*ARGSUSED*/ | |
140 | ed_delete_next_char(EditLine *el, Int c) | 140 | ed_delete_next_char(EditLine *el, Int c __attribute__((__unused__))) | |
141 | { | 141 | { | |
142 | #ifdef DEBUG_EDIT | 142 | #ifdef DEBUG_EDIT | |
143 | #define EL el->el_line | 143 | #define EL el->el_line | |
144 | (void) fprintf(el->el_errlfile, | 144 | (void) fprintf(el->el_errlfile, | |
145 | "\nD(b: %x(%s) c: %x(%s) last: %x(%s) limit: %x(%s)\n", | 145 | "\nD(b: %x(%s) c: %x(%s) last: %x(%s) limit: %x(%s)\n", | |
146 | EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar, | 146 | EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar, | |
147 | EL.lastchar, EL.limit, EL.limit); | 147 | EL.lastchar, EL.limit, EL.limit); | |
148 | #endif | 148 | #endif | |
149 | if (el->el_line.cursor == el->el_line.lastchar) { | 149 | if (el->el_line.cursor == el->el_line.lastchar) { | |
150 | /* if I'm at the end */ | 150 | /* if I'm at the end */ | |
151 | if (el->el_map.type == MAP_VI) { | 151 | if (el->el_map.type == MAP_VI) { | |
152 | if (el->el_line.cursor == el->el_line.buffer) { | 152 | if (el->el_line.cursor == el->el_line.buffer) { | |
153 | /* if I'm also at the beginning */ | 153 | /* if I'm also at the beginning */ | |
154 | #ifdef KSHVI | 154 | #ifdef KSHVI | |
155 | return CC_ERROR; | 155 | return CC_ERROR; | |
156 | #else | 156 | #else | |
157 | /* then do an EOF */ | 157 | /* then do an EOF */ | |
158 | terminal_writec(el, c); | 158 | terminal_writec(el, c); | |
159 | return CC_EOF; | 159 | return CC_EOF; | |
160 | #endif | 160 | #endif | |
161 | } else { | 161 | } else { | |
162 | #ifdef KSHVI | 162 | #ifdef KSHVI | |
163 | el->el_line.cursor--; | 163 | el->el_line.cursor--; | |
164 | #else | 164 | #else | |
165 | return CC_ERROR; | 165 | return CC_ERROR; | |
166 | #endif | 166 | #endif | |
167 | } | 167 | } | |
168 | } else { | 168 | } else { | |
169 | if (el->el_line.cursor != el->el_line.buffer) | 169 | if (el->el_line.cursor != el->el_line.buffer) | |
170 | el->el_line.cursor--; | 170 | el->el_line.cursor--; | |
171 | else | 171 | else | |
172 | return CC_ERROR; | 172 | return CC_ERROR; | |
173 | } | 173 | } | |
174 | } | 174 | } | |
175 | c_delafter(el, el->el_state.argument); /* delete after dot */ | 175 | c_delafter(el, el->el_state.argument); /* delete after dot */ | |
176 | if (el->el_line.cursor >= el->el_line.lastchar && | 176 | if (el->el_line.cursor >= el->el_line.lastchar && | |
177 | el->el_line.cursor > el->el_line.buffer) | 177 | el->el_line.cursor > el->el_line.buffer) | |
178 | /* bounds check */ | 178 | /* bounds check */ | |
179 | el->el_line.cursor = el->el_line.lastchar - 1; | 179 | el->el_line.cursor = el->el_line.lastchar - 1; | |
180 | return CC_REFRESH; | 180 | return CC_REFRESH; | |
181 | } | 181 | } | |
182 | 182 | |||
183 | 183 | |||
184 | /* ed_kill_line(): | 184 | /* ed_kill_line(): | |
185 | * Cut to the end of line | 185 | * Cut to the end of line | |
186 | * [^K] [^K] | 186 | * [^K] [^K] | |
187 | */ | 187 | */ | |
188 | protected el_action_t | 188 | protected el_action_t | |
189 | /*ARGSUSED*/ | 189 | /*ARGSUSED*/ | |
190 | ed_kill_line(EditLine *el, Int c __attribute__((__unused__))) | 190 | ed_kill_line(EditLine *el, Int c __attribute__((__unused__))) | |
191 | { | 191 | { | |
192 | Char *kp, *cp; | 192 | Char *kp, *cp; | |
193 | 193 | |||
194 | cp = el->el_line.cursor; | 194 | cp = el->el_line.cursor; | |
195 | kp = el->el_chared.c_kill.buf; | 195 | kp = el->el_chared.c_kill.buf; | |
196 | while (cp < el->el_line.lastchar) | 196 | while (cp < el->el_line.lastchar) | |
197 | *kp++ = *cp++; /* copy it */ | 197 | *kp++ = *cp++; /* copy it */ | |
198 | el->el_chared.c_kill.last = kp; | 198 | el->el_chared.c_kill.last = kp; | |
199 | /* zap! -- delete to end */ | 199 | /* zap! -- delete to end */ | |
200 | el->el_line.lastchar = el->el_line.cursor; | 200 | el->el_line.lastchar = el->el_line.cursor; | |
201 | return CC_REFRESH; | 201 | return CC_REFRESH; | |
202 | } | 202 | } | |
203 | 203 | |||
204 | 204 | |||
205 | /* ed_move_to_end(): | 205 | /* ed_move_to_end(): | |
206 | * Move cursor to the end of line | 206 | * Move cursor to the end of line | |
207 | * [^E] [^E] | 207 | * [^E] [^E] | |
208 | */ | 208 | */ | |
209 | protected el_action_t | 209 | protected el_action_t | |
210 | /*ARGSUSED*/ | 210 | /*ARGSUSED*/ | |
211 | ed_move_to_end(EditLine *el, Int c __attribute__((__unused__))) | 211 | ed_move_to_end(EditLine *el, Int c __attribute__((__unused__))) | |
212 | { | 212 | { | |
213 | 213 | |||
214 | el->el_line.cursor = el->el_line.lastchar; | 214 | el->el_line.cursor = el->el_line.lastchar; | |
215 | if (el->el_map.type == MAP_VI) { | 215 | if (el->el_map.type == MAP_VI) { | |
216 | if (el->el_chared.c_vcmd.action != NOP) { | 216 | if (el->el_chared.c_vcmd.action != NOP) { | |
217 | cv_delfini(el); | 217 | cv_delfini(el); | |
218 | return CC_REFRESH; | 218 | return CC_REFRESH; | |
219 | } | 219 | } | |
220 | #ifdef VI_MOVE | 220 | #ifdef VI_MOVE | |
221 | el->el_line.cursor--; | 221 | el->el_line.cursor--; | |
222 | #endif | 222 | #endif | |
223 | } | 223 | } | |
224 | return CC_CURSOR; | 224 | return CC_CURSOR; | |
225 | } | 225 | } | |
226 | 226 | |||
227 | 227 | |||
228 | /* ed_move_to_beg(): | 228 | /* ed_move_to_beg(): | |
229 | * Move cursor to the beginning of line | 229 | * Move cursor to the beginning of line | |
230 | * [^A] [^A] | 230 | * [^A] [^A] | |
231 | */ | 231 | */ | |
232 | protected el_action_t | 232 | protected el_action_t | |
233 | /*ARGSUSED*/ | 233 | /*ARGSUSED*/ | |
234 | ed_move_to_beg(EditLine *el, Int c __attribute__((__unused__))) | 234 | ed_move_to_beg(EditLine *el, Int c __attribute__((__unused__))) | |
235 | { | 235 | { | |
236 | 236 | |||
237 | el->el_line.cursor = el->el_line.buffer; | 237 | el->el_line.cursor = el->el_line.buffer; | |
238 | 238 | |||
239 | if (el->el_map.type == MAP_VI) { | 239 | if (el->el_map.type == MAP_VI) { | |
240 | /* We want FIRST non space character */ | 240 | /* We want FIRST non space character */ | |
241 | while (Isspace(*el->el_line.cursor)) | 241 | while (Isspace(*el->el_line.cursor)) | |
242 | el->el_line.cursor++; | 242 | el->el_line.cursor++; | |
243 | if (el->el_chared.c_vcmd.action != NOP) { | 243 | if (el->el_chared.c_vcmd.action != NOP) { | |
244 | cv_delfini(el); | 244 | cv_delfini(el); | |
245 | return CC_REFRESH; | 245 | return CC_REFRESH; | |
246 | } | 246 | } | |
247 | } | 247 | } | |
248 | return CC_CURSOR; | 248 | return CC_CURSOR; | |
249 | } | 249 | } | |
250 | 250 | |||
251 | 251 | |||
252 | /* ed_transpose_chars(): | 252 | /* ed_transpose_chars(): | |
253 | * Exchange the character to the left of the cursor with the one under it | 253 | * Exchange the character to the left of the cursor with the one under it | |
254 | * [^T] [^T] | 254 | * [^T] [^T] | |
255 | */ | 255 | */ | |
256 | protected el_action_t | 256 | protected el_action_t | |
257 | ed_transpose_chars(EditLine *el, Int c) | 257 | ed_transpose_chars(EditLine *el, Int c) | |
258 | { | 258 | { | |
259 | 259 | |||
260 | if (el->el_line.cursor < el->el_line.lastchar) { | 260 | if (el->el_line.cursor < el->el_line.lastchar) { | |
261 | if (el->el_line.lastchar <= &el->el_line.buffer[1]) | 261 | if (el->el_line.lastchar <= &el->el_line.buffer[1]) | |
262 | return CC_ERROR; | 262 | return CC_ERROR; | |
263 | else | 263 | else | |
264 | el->el_line.cursor++; | 264 | el->el_line.cursor++; | |
265 | } | 265 | } | |
266 | if (el->el_line.cursor > &el->el_line.buffer[1]) { | 266 | if (el->el_line.cursor > &el->el_line.buffer[1]) { | |
267 | /* must have at least two chars entered */ | 267 | /* must have at least two chars entered */ | |
268 | c = el->el_line.cursor[-2]; | 268 | c = el->el_line.cursor[-2]; | |
269 | el->el_line.cursor[-2] = el->el_line.cursor[-1]; | 269 | el->el_line.cursor[-2] = el->el_line.cursor[-1]; | |
270 | el->el_line.cursor[-1] = c; | 270 | el->el_line.cursor[-1] = c; | |
271 | return CC_REFRESH; | 271 | return CC_REFRESH; | |
272 | } else | 272 | } else | |
273 | return CC_ERROR; | 273 | return CC_ERROR; | |
274 | } | 274 | } | |
275 | 275 | |||
276 | 276 | |||
277 | /* ed_next_char(): | 277 | /* ed_next_char(): | |
278 | * Move to the right one character | 278 | * Move to the right one character | |
279 | * [^F] [^F] | 279 | * [^F] [^F] | |
280 | */ | 280 | */ | |
281 | protected el_action_t | 281 | protected el_action_t | |
282 | /*ARGSUSED*/ | 282 | /*ARGSUSED*/ | |
283 | ed_next_char(EditLine *el, Int c __attribute__((__unused__))) | 283 | ed_next_char(EditLine *el, Int c __attribute__((__unused__))) | |
284 | { | 284 | { | |
285 | Char *lim = el->el_line.lastchar; | 285 | Char *lim = el->el_line.lastchar; | |
286 | 286 | |||
287 | if (el->el_line.cursor >= lim || | 287 | if (el->el_line.cursor >= lim || | |
288 | (el->el_line.cursor == lim - 1 && | 288 | (el->el_line.cursor == lim - 1 && | |
289 | el->el_map.type == MAP_VI && | 289 | el->el_map.type == MAP_VI && | |
290 | el->el_chared.c_vcmd.action == NOP)) | 290 | el->el_chared.c_vcmd.action == NOP)) | |
291 | return CC_ERROR; | 291 | return CC_ERROR; | |
292 | 292 | |||
293 | el->el_line.cursor += el->el_state.argument; | 293 | el->el_line.cursor += el->el_state.argument; | |
294 | if (el->el_line.cursor > lim) | 294 | if (el->el_line.cursor > lim) | |
295 | el->el_line.cursor = lim; | 295 | el->el_line.cursor = lim; | |
296 | 296 | |||
297 | if (el->el_map.type == MAP_VI) | 297 | if (el->el_map.type == MAP_VI) | |
298 | if (el->el_chared.c_vcmd.action != NOP) { | 298 | if (el->el_chared.c_vcmd.action != NOP) { | |
299 | cv_delfini(el); | 299 | cv_delfini(el); | |
300 | return CC_REFRESH; | 300 | return CC_REFRESH; | |
301 | } | 301 | } | |
302 | return CC_CURSOR; | 302 | return CC_CURSOR; | |
303 | } | 303 | } | |
304 | 304 | |||
305 | 305 | |||
306 | /* ed_prev_word(): | 306 | /* ed_prev_word(): | |
307 | * Move to the beginning of the current word | 307 | * Move to the beginning of the current word | |
308 | * [M-b] [b] | 308 | * [M-b] [b] | |
309 | */ | 309 | */ | |
310 | protected el_action_t | 310 | protected el_action_t | |
311 | /*ARGSUSED*/ | 311 | /*ARGSUSED*/ | |
312 | ed_prev_word(EditLine *el, Int c __attribute__((__unused__))) | 312 | ed_prev_word(EditLine *el, Int c __attribute__((__unused__))) | |
313 | { | 313 | { | |
314 | 314 | |||
315 | if (el->el_line.cursor == el->el_line.buffer) | 315 | if (el->el_line.cursor == el->el_line.buffer) | |
316 | return CC_ERROR; | 316 | return CC_ERROR; | |
317 | 317 | |||
318 | el->el_line.cursor = c__prev_word(el->el_line.cursor, | 318 | el->el_line.cursor = c__prev_word(el->el_line.cursor, | |
319 | el->el_line.buffer, | 319 | el->el_line.buffer, | |
320 | el->el_state.argument, | 320 | el->el_state.argument, | |
321 | ce__isword); | 321 | ce__isword); | |
322 | 322 | |||
323 | if (el->el_map.type == MAP_VI) | 323 | if (el->el_map.type == MAP_VI) | |
324 | if (el->el_chared.c_vcmd.action != NOP) { | 324 | if (el->el_chared.c_vcmd.action != NOP) { | |
325 | cv_delfini(el); | 325 | cv_delfini(el); | |
326 | return CC_REFRESH; | 326 | return CC_REFRESH; | |
327 | } | 327 | } | |
328 | return CC_CURSOR; | 328 | return CC_CURSOR; | |
329 | } | 329 | } | |
330 | 330 | |||
331 | 331 | |||
332 | /* ed_prev_char(): | 332 | /* ed_prev_char(): | |
333 | * Move to the left one character | 333 | * Move to the left one character | |
334 | * [^B] [^B] | 334 | * [^B] [^B] | |
335 | */ | 335 | */ | |
336 | protected el_action_t | 336 | protected el_action_t | |
337 | /*ARGSUSED*/ | 337 | /*ARGSUSED*/ | |
338 | ed_prev_char(EditLine *el, Int c __attribute__((__unused__))) | 338 | ed_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
339 | { | 339 | { | |
340 | 340 | |||
341 | if (el->el_line.cursor > el->el_line.buffer) { | 341 | if (el->el_line.cursor > el->el_line.buffer) { | |
342 | el->el_line.cursor -= el->el_state.argument; | 342 | el->el_line.cursor -= el->el_state.argument; | |
343 | if (el->el_line.cursor < el->el_line.buffer) | 343 | if (el->el_line.cursor < el->el_line.buffer) | |
344 | el->el_line.cursor = el->el_line.buffer; | 344 | el->el_line.cursor = el->el_line.buffer; | |
345 | 345 | |||
346 | if (el->el_map.type == MAP_VI) | 346 | if (el->el_map.type == MAP_VI) | |
347 | if (el->el_chared.c_vcmd.action != NOP) { | 347 | if (el->el_chared.c_vcmd.action != NOP) { | |
348 | cv_delfini(el); | 348 | cv_delfini(el); | |
349 | return CC_REFRESH; | 349 | return CC_REFRESH; | |
350 | } | 350 | } | |
351 | return CC_CURSOR; | 351 | return CC_CURSOR; | |
352 | } else | 352 | } else | |
353 | return CC_ERROR; | 353 | return CC_ERROR; | |
354 | } | 354 | } | |
355 | 355 | |||
356 | 356 | |||
357 | /* ed_quoted_insert(): | 357 | /* ed_quoted_insert(): | |
358 | * Add the next character typed verbatim | 358 | * Add the next character typed verbatim | |
359 | * [^V] [^V] | 359 | * [^V] [^V] | |
360 | */ | 360 | */ | |
361 | protected el_action_t | 361 | protected el_action_t | |
362 | ed_quoted_insert(EditLine *el, Int c) | 362 | ed_quoted_insert(EditLine *el, Int c) | |
363 | { | 363 | { | |
364 | int num; | 364 | int num; | |
365 | Char tc; | 365 | Char tc; | |
366 | 366 | |||
367 | tty_quotemode(el); | 367 | tty_quotemode(el); | |
368 | num = FUN(el,getc)(el, &tc); | 368 | num = FUN(el,getc)(el, &tc); | |
369 | c = tc; | 369 | c = tc; | |
370 | tty_noquotemode(el); | 370 | tty_noquotemode(el); | |
371 | if (num == 1) | 371 | if (num == 1) | |
372 | return ed_insert(el, c); | 372 | return ed_insert(el, c); | |
373 | else | 373 | else | |
374 | return ed_end_of_file(el, 0); | 374 | return ed_end_of_file(el, 0); | |
375 | } | 375 | } | |
376 | 376 | |||
377 | 377 | |||
378 | /* ed_digit(): | 378 | /* ed_digit(): | |
379 | * Adds to argument or enters a digit | 379 | * Adds to argument or enters a digit | |
380 | */ | 380 | */ | |
381 | protected el_action_t | 381 | protected el_action_t | |
382 | ed_digit(EditLine *el, Int c) | 382 | ed_digit(EditLine *el, Int c) | |
383 | { | 383 | { | |
384 | 384 | |||
385 | if (!Isdigit(c)) | 385 | if (!Isdigit(c)) | |
386 | return CC_ERROR; | 386 | return CC_ERROR; | |
387 | 387 | |||
388 | if (el->el_state.doingarg) { | 388 | if (el->el_state.doingarg) { | |
389 | /* if doing an arg, add this in... */ | 389 | /* if doing an arg, add this in... */ | |
390 | if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT) | 390 | if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT) | |
391 | el->el_state.argument = c - '0'; | 391 | el->el_state.argument = c - '0'; | |
392 | else { | 392 | else { | |
393 | if (el->el_state.argument > 1000000) | 393 | if (el->el_state.argument > 1000000) | |
394 | return CC_ERROR; | 394 | return CC_ERROR; | |
395 | el->el_state.argument = | 395 | el->el_state.argument = | |
396 | (el->el_state.argument * 10) + (c - '0'); | 396 | (el->el_state.argument * 10) + (c - '0'); | |
397 | } | 397 | } | |
398 | return CC_ARGHACK; | 398 | return CC_ARGHACK; | |
399 | } | 399 | } | |
400 | 400 | |||
401 | return ed_insert(el, c); | 401 | return ed_insert(el, c); | |
402 | } | 402 | } | |
403 | 403 | |||
404 | 404 | |||
405 | /* ed_argument_digit(): | 405 | /* ed_argument_digit(): | |
406 | * Digit that starts argument | 406 | * Digit that starts argument | |
407 | * For ESC-n | 407 | * For ESC-n | |
408 | */ | 408 | */ | |
409 | protected el_action_t | 409 | protected el_action_t | |
410 | ed_argument_digit(EditLine *el, Int c) | 410 | ed_argument_digit(EditLine *el, Int c) | |
411 | { | 411 | { | |
412 | 412 | |||
413 | if (!Isdigit(c)) | 413 | if (!Isdigit(c)) | |
414 | return CC_ERROR; | 414 | return CC_ERROR; | |
415 | 415 | |||
416 | if (el->el_state.doingarg) { | 416 | if (el->el_state.doingarg) { | |
417 | if (el->el_state.argument > 1000000) | 417 | if (el->el_state.argument > 1000000) | |
418 | return CC_ERROR; | 418 | return CC_ERROR; | |
419 | el->el_state.argument = (el->el_state.argument * 10) + | 419 | el->el_state.argument = (el->el_state.argument * 10) + | |
420 | (c - '0'); | 420 | (c - '0'); | |
421 | } else { /* else starting an argument */ | 421 | } else { /* else starting an argument */ | |
422 | el->el_state.argument = c - '0'; | 422 | el->el_state.argument = c - '0'; | |
423 | el->el_state.doingarg = 1; | 423 | el->el_state.doingarg = 1; | |
424 | } | 424 | } | |
425 | return CC_ARGHACK; | 425 | return CC_ARGHACK; | |
426 | } | 426 | } | |
427 | 427 | |||
428 | 428 | |||
429 | /* ed_unassigned(): | 429 | /* ed_unassigned(): | |
430 | * Indicates unbound character | 430 | * Indicates unbound character | |
431 | * Bound to keys that are not assigned | 431 | * Bound to keys that are not assigned | |
432 | */ | 432 | */ | |
433 | protected el_action_t | 433 | protected el_action_t | |
434 | /*ARGSUSED*/ | 434 | /*ARGSUSED*/ | |
435 | ed_unassigned(EditLine *el, Int c __attribute__((__unused__))) | 435 | ed_unassigned(EditLine *el __attribute__((__unused__)), | |
436 | Int c __attribute__((__unused__))) | |||
436 | { | 437 | { | |
437 | 438 | |||
438 | return CC_ERROR; | 439 | return CC_ERROR; | |
439 | } | 440 | } | |
440 | 441 | |||
441 | 442 | |||
442 | /** | 443 | /** | |
443 | ** TTY key handling. | 444 | ** TTY key handling. | |
444 | **/ | 445 | **/ | |
445 | 446 | |||
446 | /* ed_tty_sigint(): | 447 | /* ed_tty_sigint(): | |
447 | * Tty interrupt character | 448 | * Tty interrupt character | |
448 | * [^C] | 449 | * [^C] | |
449 | */ | 450 | */ | |
450 | protected el_action_t | 451 | protected el_action_t | |
451 | /*ARGSUSED*/ | 452 | /*ARGSUSED*/ | |
452 | ed_tty_sigint(EditLine *el __attribute__((__unused__)), | 453 | ed_tty_sigint(EditLine *el __attribute__((__unused__)), | |
453 | Int c __attribute__((__unused__))) | 454 | Int c __attribute__((__unused__))) | |
454 | { | 455 | { | |
455 | 456 | |||
456 | return CC_NORM; | 457 | return CC_NORM; | |
457 | } | 458 | } | |
458 | 459 | |||
459 | 460 | |||
460 | /* ed_tty_dsusp(): | 461 | /* ed_tty_dsusp(): | |
461 | * Tty delayed suspend character | 462 | * Tty delayed suspend character | |
462 | * [^Y] | 463 | * [^Y] | |
463 | */ | 464 | */ | |
464 | protected el_action_t | 465 | protected el_action_t | |
465 | /*ARGSUSED*/ | 466 | /*ARGSUSED*/ | |
466 | ed_tty_dsusp(EditLine *el __attribute__((__unused__)), | 467 | ed_tty_dsusp(EditLine *el __attribute__((__unused__)), | |
467 | Int c __attribute__((__unused__))) | 468 | Int c __attribute__((__unused__))) | |
468 | { | 469 | { | |
469 | 470 | |||
470 | return CC_NORM; | 471 | return CC_NORM; | |
471 | } | 472 | } | |
472 | 473 | |||
473 | 474 | |||
474 | /* ed_tty_flush_output(): | 475 | /* ed_tty_flush_output(): | |
475 | * Tty flush output characters | 476 | * Tty flush output characters | |
476 | * [^O] | 477 | * [^O] | |
477 | */ | 478 | */ | |
478 | protected el_action_t | 479 | protected el_action_t | |
479 | /*ARGSUSED*/ | 480 | /*ARGSUSED*/ | |
480 | ed_tty_flush_output(EditLine *el __attribute__((__unused__)), | 481 | ed_tty_flush_output(EditLine *el __attribute__((__unused__)), | |
481 | Int c __attribute__((__unused__))) | 482 | Int c __attribute__((__unused__))) | |
482 | { | 483 | { | |
483 | 484 | |||
484 | return CC_NORM; | 485 | return CC_NORM; | |
485 | } | 486 | } | |
486 | 487 | |||
487 | 488 | |||
488 | /* ed_tty_sigquit(): | 489 | /* ed_tty_sigquit(): | |
489 | * Tty quit character | 490 | * Tty quit character | |
490 | * [^\] | 491 | * [^\] | |
491 | */ | 492 | */ | |
492 | protected el_action_t | 493 | protected el_action_t | |
493 | /*ARGSUSED*/ | 494 | /*ARGSUSED*/ | |
494 | ed_tty_sigquit(EditLine *el __attribute__((__unused__)), | 495 | ed_tty_sigquit(EditLine *el __attribute__((__unused__)), | |
495 | Int c __attribute__((__unused__))) | 496 | Int c __attribute__((__unused__))) | |
496 | { | 497 | { | |
497 | 498 | |||
498 | return CC_NORM; | 499 | return CC_NORM; | |
499 | } | 500 | } | |
500 | 501 | |||
501 | 502 | |||
502 | /* ed_tty_sigtstp(): | 503 | /* ed_tty_sigtstp(): | |
503 | * Tty suspend character | 504 | * Tty suspend character | |
504 | * [^Z] | 505 | * [^Z] | |
505 | */ | 506 | */ | |
506 | protected el_action_t | 507 | protected el_action_t | |
507 | /*ARGSUSED*/ | 508 | /*ARGSUSED*/ | |
508 | ed_tty_sigtstp(EditLine *el __attribute__((__unused__)), | 509 | ed_tty_sigtstp(EditLine *el __attribute__((__unused__)), | |
509 | Int c __attribute__((__unused__))) | 510 | Int c __attribute__((__unused__))) | |
510 | { | 511 | { | |
511 | 512 | |||
512 | return CC_NORM; | 513 | return CC_NORM; | |
513 | } | 514 | } | |
514 | 515 | |||
515 | 516 | |||
516 | /* ed_tty_stop_output(): | 517 | /* ed_tty_stop_output(): | |
517 | * Tty disallow output characters | 518 | * Tty disallow output characters | |
518 | * [^S] | 519 | * [^S] | |
519 | */ | 520 | */ | |
520 | protected el_action_t | 521 | protected el_action_t | |
521 | /*ARGSUSED*/ | 522 | /*ARGSUSED*/ | |
522 | ed_tty_stop_output(EditLine *el __attribute__((__unused__)), | 523 | ed_tty_stop_output(EditLine *el __attribute__((__unused__)), | |
523 | Int c __attribute__((__unused__))) | 524 | Int c __attribute__((__unused__))) | |
524 | { | 525 | { | |
525 | 526 | |||
526 | return CC_NORM; | 527 | return CC_NORM; | |
527 | } | 528 | } | |
528 | 529 | |||
529 | 530 | |||
530 | /* ed_tty_start_output(): | 531 | /* ed_tty_start_output(): | |
531 | * Tty allow output characters | 532 | * Tty allow output characters | |
532 | * [^Q] | 533 | * [^Q] | |
533 | */ | 534 | */ | |
534 | protected el_action_t | 535 | protected el_action_t | |
535 | /*ARGSUSED*/ | 536 | /*ARGSUSED*/ | |
536 | ed_tty_start_output(EditLine *el __attribute__((__unused__)), | 537 | ed_tty_start_output(EditLine *el __attribute__((__unused__)), | |
537 | Int c __attribute__((__unused__))) | 538 | Int c __attribute__((__unused__))) | |
538 | { | 539 | { | |
539 | 540 | |||
540 | return CC_NORM; | 541 | return CC_NORM; | |
541 | } | 542 | } | |
542 | 543 | |||
543 | 544 | |||
544 | /* ed_newline(): | 545 | /* ed_newline(): | |
545 | * Execute command | 546 | * Execute command | |
546 | * [^J] | 547 | * [^J] | |
547 | */ | 548 | */ | |
548 | protected el_action_t | 549 | protected el_action_t | |
549 | /*ARGSUSED*/ | 550 | /*ARGSUSED*/ | |
550 | ed_newline(EditLine *el, Int c __attribute__((__unused__))) | 551 | ed_newline(EditLine *el, Int c __attribute__((__unused__))) | |
551 | { | 552 | { | |
552 | 553 | |||
553 | re_goto_bottom(el); | 554 | re_goto_bottom(el); | |
554 | *el->el_line.lastchar++ = '\n'; | 555 | *el->el_line.lastchar++ = '\n'; | |
555 | *el->el_line.lastchar = '\0'; | 556 | *el->el_line.lastchar = '\0'; | |
556 | return CC_NEWLINE; | 557 | return CC_NEWLINE; | |
557 | } | 558 | } | |
558 | 559 | |||
559 | 560 | |||
560 | /* ed_delete_prev_char(): | 561 | /* ed_delete_prev_char(): | |
561 | * Delete the character to the left of the cursor | 562 | * Delete the character to the left of the cursor | |
562 | * [^?] | 563 | * [^?] | |
563 | */ | 564 | */ | |
564 | protected el_action_t | 565 | protected el_action_t | |
565 | /*ARGSUSED*/ | 566 | /*ARGSUSED*/ | |
566 | ed_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) | 567 | ed_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
567 | { | 568 | { | |
568 | 569 | |||
569 | if (el->el_line.cursor <= el->el_line.buffer) | 570 | if (el->el_line.cursor <= el->el_line.buffer) | |
570 | return CC_ERROR; | 571 | return CC_ERROR; | |
571 | 572 | |||
572 | c_delbefore(el, el->el_state.argument); | 573 | c_delbefore(el, el->el_state.argument); | |
573 | el->el_line.cursor -= el->el_state.argument; | 574 | el->el_line.cursor -= el->el_state.argument; | |
574 | if (el->el_line.cursor < el->el_line.buffer) | 575 | if (el->el_line.cursor < el->el_line.buffer) | |
575 | el->el_line.cursor = el->el_line.buffer; | 576 | el->el_line.cursor = el->el_line.buffer; | |
576 | return CC_REFRESH; | 577 | return CC_REFRESH; | |
577 | } | 578 | } | |
578 | 579 | |||
579 | 580 | |||
580 | /* ed_clear_screen(): | 581 | /* ed_clear_screen(): | |
581 | * Clear screen leaving current line at the top | 582 | * Clear screen leaving current line at the top | |
582 | * [^L] | 583 | * [^L] | |
583 | */ | 584 | */ | |
584 | protected el_action_t | 585 | protected el_action_t | |
585 | /*ARGSUSED*/ | 586 | /*ARGSUSED*/ | |
586 | ed_clear_screen(EditLine *el, Int c __attribute__((__unused__))) | 587 | ed_clear_screen(EditLine *el, Int c __attribute__((__unused__))) | |
587 | { | 588 | { | |
588 | 589 | |||
589 | terminal_clear_screen(el); /* clear the whole real screen */ | 590 | terminal_clear_screen(el); /* clear the whole real screen */ | |
590 | re_clear_display(el); /* reset everything */ | 591 | re_clear_display(el); /* reset everything */ | |
591 | return CC_REFRESH; | 592 | return CC_REFRESH; | |
592 | } | 593 | } | |
593 | 594 | |||
594 | 595 | |||
595 | /* ed_redisplay(): | 596 | /* ed_redisplay(): | |
596 | * Redisplay everything | 597 | * Redisplay everything | |
597 | * ^R | 598 | * ^R | |
598 | */ | 599 | */ | |
599 | protected el_action_t | 600 | protected el_action_t | |
600 | /*ARGSUSED*/ | 601 | /*ARGSUSED*/ | |
601 | ed_redisplay(EditLine *el __attribute__((__unused__)), | 602 | ed_redisplay(EditLine *el __attribute__((__unused__)), | |
602 | Int c __attribute__((__unused__))) | 603 | Int c __attribute__((__unused__))) | |
603 | { | 604 | { | |
604 | 605 | |||
605 | return CC_REDISPLAY; | 606 | return CC_REDISPLAY; | |
606 | } | 607 | } | |
607 | 608 | |||
608 | 609 | |||
609 | /* ed_start_over(): | 610 | /* ed_start_over(): | |
610 | * Erase current line and start from scratch | 611 | * Erase current line and start from scratch | |
611 | * [^G] | 612 | * [^G] | |
612 | */ | 613 | */ | |
613 | protected el_action_t | 614 | protected el_action_t | |
614 | /*ARGSUSED*/ | 615 | /*ARGSUSED*/ | |
615 | ed_start_over(EditLine *el, Int c __attribute__((__unused__))) | 616 | ed_start_over(EditLine *el, Int c __attribute__((__unused__))) | |
616 | { | 617 | { | |
617 | 618 | |||
618 | ch_reset(el, 0); | 619 | ch_reset(el, 0); | |
619 | return CC_REFRESH; | 620 | return CC_REFRESH; | |
620 | } | 621 | } | |
621 | 622 | |||
622 | 623 | |||
623 | /* ed_sequence_lead_in(): | 624 | /* ed_sequence_lead_in(): | |
624 | * First character in a bound sequence | 625 | * First character in a bound sequence | |
625 | * Placeholder for external keys | 626 | * Placeholder for external keys | |
626 | */ | 627 | */ | |
627 | protected el_action_t | 628 | protected el_action_t | |
628 | /*ARGSUSED*/ | 629 | /*ARGSUSED*/ | |
629 | ed_sequence_lead_in(EditLine *el __attribute__((__unused__)), | 630 | ed_sequence_lead_in(EditLine *el __attribute__((__unused__)), | |
630 | Int c __attribute__((__unused__))) | 631 | Int c __attribute__((__unused__))) | |
631 | { | 632 | { | |
632 | 633 | |||
633 | return CC_NORM; | 634 | return CC_NORM; | |
634 | } | 635 | } | |
635 | 636 | |||
636 | 637 | |||
637 | /* ed_prev_history(): | 638 | /* ed_prev_history(): | |
638 | * Move to the previous history line | 639 | * Move to the previous history line | |
639 | * [^P] [k] | 640 | * [^P] [k] | |
640 | */ | 641 | */ | |
641 | protected el_action_t | 642 | protected el_action_t | |
642 | /*ARGSUSED*/ | 643 | /*ARGSUSED*/ | |
643 | ed_prev_history(EditLine *el, Int c __attribute__((__unused__))) | 644 | ed_prev_history(EditLine *el, Int c __attribute__((__unused__))) | |
644 | { | 645 | { | |
645 | char beep = 0; | 646 | char beep = 0; | |
646 | int sv_event = el->el_history.eventno; | 647 | int sv_event = el->el_history.eventno; | |
647 | 648 | |||
648 | el->el_chared.c_undo.len = -1; | 649 | el->el_chared.c_undo.len = -1; | |
649 | *el->el_line.lastchar = '\0'; /* just in case */ | 650 | *el->el_line.lastchar = '\0'; /* just in case */ | |
650 | 651 | |||
651 | if (el->el_history.eventno == 0) { /* save the current buffer | 652 | if (el->el_history.eventno == 0) { /* save the current buffer | |
652 | * away */ | 653 | * away */ | |
653 | (void) Strncpy(el->el_history.buf, el->el_line.buffer, | 654 | (void) Strncpy(el->el_history.buf, el->el_line.buffer, | |
654 | EL_BUFSIZ); | 655 | EL_BUFSIZ); | |
655 | el->el_history.last = el->el_history.buf + | 656 | el->el_history.last = el->el_history.buf + | |
656 | (el->el_line.lastchar - el->el_line.buffer); | 657 | (el->el_line.lastchar - el->el_line.buffer); | |
657 | } | 658 | } | |
658 | el->el_history.eventno += el->el_state.argument; | 659 | el->el_history.eventno += el->el_state.argument; | |
659 | 660 | |||
660 | if (hist_get(el) == CC_ERROR) { | 661 | if (hist_get(el) == CC_ERROR) { | |
661 | if (el->el_map.type == MAP_VI) { | 662 | if (el->el_map.type == MAP_VI) { | |
662 | el->el_history.eventno = sv_event; | 663 | el->el_history.eventno = sv_event; | |
663 | 664 | |||
664 | } | 665 | } | |
665 | beep = 1; | 666 | beep = 1; | |
666 | /* el->el_history.eventno was fixed by first call */ | 667 | /* el->el_history.eventno was fixed by first call */ | |
667 | (void) hist_get(el); | 668 | (void) hist_get(el); | |
668 | } | 669 | } | |
669 | if (beep) | 670 | if (beep) | |
670 | return CC_REFRESH_BEEP; | 671 | return CC_REFRESH_BEEP; | |
671 | return CC_REFRESH; | 672 | return CC_REFRESH; | |
672 | } | 673 | } | |
673 | 674 | |||
674 | 675 | |||
675 | /* ed_next_history(): | 676 | /* ed_next_history(): | |
676 | * Move to the next history line | 677 | * Move to the next history line | |
677 | * [^N] [j] | 678 | * [^N] [j] | |
678 | */ | 679 | */ | |
679 | protected el_action_t | 680 | protected el_action_t | |
680 | /*ARGSUSED*/ | 681 | /*ARGSUSED*/ | |
681 | ed_next_history(EditLine *el, Int c __attribute__((__unused__))) | 682 | ed_next_history(EditLine *el, Int c __attribute__((__unused__))) | |
682 | { | 683 | { | |
683 | el_action_t beep = CC_REFRESH, rval; | 684 | el_action_t beep = CC_REFRESH, rval; | |
684 | 685 | |||
685 | el->el_chared.c_undo.len = -1; | 686 | el->el_chared.c_undo.len = -1; | |
686 | *el->el_line.lastchar = '\0'; /* just in case */ | 687 | *el->el_line.lastchar = '\0'; /* just in case */ | |
687 | 688 | |||
688 | el->el_history.eventno -= el->el_state.argument; | 689 | el->el_history.eventno -= el->el_state.argument; | |
689 | 690 | |||
690 | if (el->el_history.eventno < 0) { | 691 | if (el->el_history.eventno < 0) { | |
691 | el->el_history.eventno = 0; | 692 | el->el_history.eventno = 0; | |
692 | beep = CC_REFRESH_BEEP; | 693 | beep = CC_REFRESH_BEEP; | |
693 | } | 694 | } | |
694 | rval = hist_get(el); | 695 | rval = hist_get(el); | |
695 | if (rval == CC_REFRESH) | 696 | if (rval == CC_REFRESH) | |
696 | return beep; | 697 | return beep; | |
697 | return rval; | 698 | return rval; | |
698 | 699 | |||
699 | } | 700 | } | |
700 | 701 | |||
701 | 702 | |||
702 | /* ed_search_prev_history(): | 703 | /* ed_search_prev_history(): | |
703 | * Search previous in history for a line matching the current | 704 | * Search previous in history for a line matching the current | |
704 | * next search history [M-P] [K] | 705 | * next search history [M-P] [K] | |
705 | */ | 706 | */ | |
706 | protected el_action_t | 707 | protected el_action_t | |
707 | /*ARGSUSED*/ | 708 | /*ARGSUSED*/ | |
708 | ed_search_prev_history(EditLine *el, Int c __attribute__((__unused__))) | 709 | ed_search_prev_history(EditLine *el, Int c __attribute__((__unused__))) | |
709 | { | 710 | { | |
710 | const Char *hp; | 711 | const Char *hp; | |
711 | int h; | 712 | int h; | |
712 | bool_t found = 0; | 713 | bool_t found = 0; | |
713 | 714 | |||
714 | el->el_chared.c_vcmd.action = NOP; | 715 | el->el_chared.c_vcmd.action = NOP; | |
715 | el->el_chared.c_undo.len = -1; | 716 | el->el_chared.c_undo.len = -1; | |
716 | *el->el_line.lastchar = '\0'; /* just in case */ | 717 | *el->el_line.lastchar = '\0'; /* just in case */ | |
717 | if (el->el_history.eventno < 0) { | 718 | if (el->el_history.eventno < 0) { | |
718 | #ifdef DEBUG_EDIT | 719 | #ifdef DEBUG_EDIT | |
719 | (void) fprintf(el->el_errfile, | 720 | (void) fprintf(el->el_errfile, | |
720 | "e_prev_search_hist(): eventno < 0;\n"); | 721 | "e_prev_search_hist(): eventno < 0;\n"); | |
721 | #endif | 722 | #endif | |
722 | el->el_history.eventno = 0; | 723 | el->el_history.eventno = 0; | |
723 | return CC_ERROR; | 724 | return CC_ERROR; | |
724 | } | 725 | } | |
725 | if (el->el_history.eventno == 0) { | 726 | if (el->el_history.eventno == 0) { | |
726 | (void) Strncpy(el->el_history.buf, el->el_line.buffer, | 727 | (void) Strncpy(el->el_history.buf, el->el_line.buffer, | |
727 | EL_BUFSIZ); | 728 | EL_BUFSIZ); | |
728 | el->el_history.last = el->el_history.buf + | 729 | el->el_history.last = el->el_history.buf + | |
729 | (el->el_line.lastchar - el->el_line.buffer); | 730 | (el->el_line.lastchar - el->el_line.buffer); | |
730 | } | 731 | } | |
731 | if (el->el_history.ref == NULL) | 732 | if (el->el_history.ref == NULL) | |
732 | return CC_ERROR; | 733 | return CC_ERROR; | |
733 | 734 | |||
734 | hp = HIST_FIRST(el); | 735 | hp = HIST_FIRST(el); | |
735 | if (hp == NULL) | 736 | if (hp == NULL) | |
736 | return CC_ERROR; | 737 | return CC_ERROR; | |
737 | 738 | |||
738 | c_setpat(el); /* Set search pattern !! */ | 739 | c_setpat(el); /* Set search pattern !! */ | |
739 | 740 | |||
740 | for (h = 1; h <= el->el_history.eventno; h++) | 741 | for (h = 1; h <= el->el_history.eventno; h++) | |
741 | hp = HIST_NEXT(el); | 742 | hp = HIST_NEXT(el); | |
742 | 743 | |||
743 | while (hp != NULL) { | 744 | while (hp != NULL) { | |
744 | #ifdef SDEBUG | 745 | #ifdef SDEBUG | |
745 | (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); | 746 | (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); | |
746 | #endif | 747 | #endif | |
747 | if ((Strncmp(hp, el->el_line.buffer, (size_t) | 748 | if ((Strncmp(hp, el->el_line.buffer, (size_t) | |
748 | (el->el_line.lastchar - el->el_line.buffer)) || | 749 | (el->el_line.lastchar - el->el_line.buffer)) || | |
749 | hp[el->el_line.lastchar - el->el_line.buffer]) && | 750 | hp[el->el_line.lastchar - el->el_line.buffer]) && | |
750 | c_hmatch(el, hp)) { | 751 | c_hmatch(el, hp)) { | |
751 | found++; | 752 | found++; | |
752 | break; | 753 | break; | |
753 | } | 754 | } | |
754 | h++; | 755 | h++; | |
755 | hp = HIST_NEXT(el); | 756 | hp = HIST_NEXT(el); | |
756 | } | 757 | } | |
757 | 758 | |||
758 | if (!found) { | 759 | if (!found) { | |
759 | #ifdef SDEBUG | 760 | #ifdef SDEBUG | |
760 | (void) fprintf(el->el_errfile, "not found\n"); | 761 | (void) fprintf(el->el_errfile, "not found\n"); | |
761 | #endif | 762 | #endif | |
762 | return CC_ERROR; | 763 | return CC_ERROR; | |
763 | } | 764 | } | |
764 | el->el_history.eventno = h; | 765 | el->el_history.eventno = h; | |
765 | 766 | |||
766 | return hist_get(el); | 767 | return hist_get(el); | |
767 | } | 768 | } | |
768 | 769 | |||
769 | 770 | |||
770 | /* ed_search_next_history(): | 771 | /* ed_search_next_history(): | |
771 | * Search next in history for a line matching the current | 772 | * Search next in history for a line matching the current | |
772 | * [M-N] [J] | 773 | * [M-N] [J] | |
773 | */ | 774 | */ | |
774 | protected el_action_t | 775 | protected el_action_t | |
775 | /*ARGSUSED*/ | 776 | /*ARGSUSED*/ | |
776 | ed_search_next_history(EditLine *el, Int c __attribute__((__unused__))) | 777 | ed_search_next_history(EditLine *el, Int c __attribute__((__unused__))) | |
777 | { | 778 | { | |
778 | const Char *hp; | 779 | const Char *hp; | |
779 | int h; | 780 | int h; | |
780 | bool_t found = 0; | 781 | bool_t found = 0; | |
781 | 782 | |||
782 | el->el_chared.c_vcmd.action = NOP; | 783 | el->el_chared.c_vcmd.action = NOP; | |
783 | el->el_chared.c_undo.len = -1; | 784 | el->el_chared.c_undo.len = -1; | |
784 | *el->el_line.lastchar = '\0'; /* just in case */ | 785 | *el->el_line.lastchar = '\0'; /* just in case */ | |
785 | 786 | |||
786 | if (el->el_history.eventno == 0) | 787 | if (el->el_history.eventno == 0) | |
787 | return CC_ERROR; | 788 | return CC_ERROR; | |
788 | 789 | |||
789 | if (el->el_history.ref == NULL) | 790 | if (el->el_history.ref == NULL) | |
790 | return CC_ERROR; | 791 | return CC_ERROR; | |
791 | 792 | |||
792 | hp = HIST_FIRST(el); | 793 | hp = HIST_FIRST(el); | |
793 | if (hp == NULL) | 794 | if (hp == NULL) | |
794 | return CC_ERROR; | 795 | return CC_ERROR; | |
795 | 796 | |||
796 | c_setpat(el); /* Set search pattern !! */ | 797 | c_setpat(el); /* Set search pattern !! */ | |
797 | 798 | |||
798 | for (h = 1; h < el->el_history.eventno && hp; h++) { | 799 | for (h = 1; h < el->el_history.eventno && hp; h++) { | |
799 | #ifdef SDEBUG | 800 | #ifdef SDEBUG | |
800 | (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); | 801 | (void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); | |
801 | #endif | 802 | #endif | |
802 | if ((Strncmp(hp, el->el_line.buffer, (size_t) | 803 | if ((Strncmp(hp, el->el_line.buffer, (size_t) | |
803 | (el->el_line.lastchar - el->el_line.buffer)) || | 804 | (el->el_line.lastchar - el->el_line.buffer)) || | |
804 | hp[el->el_line.lastchar - el->el_line.buffer]) && | 805 | hp[el->el_line.lastchar - el->el_line.buffer]) && | |
805 | c_hmatch(el, hp)) | 806 | c_hmatch(el, hp)) | |
806 | found = h; | 807 | found = h; | |
807 | hp = HIST_NEXT(el); | 808 | hp = HIST_NEXT(el); | |
808 | } | 809 | } | |
809 | 810 | |||
810 | if (!found) { /* is it the current history number? */ | 811 | if (!found) { /* is it the current history number? */ | |
811 | if (!c_hmatch(el, el->el_history.buf)) { | 812 | if (!c_hmatch(el, el->el_history.buf)) { | |
812 | #ifdef SDEBUG | 813 | #ifdef SDEBUG | |
813 | (void) fprintf(el->el_errfile, "not found\n"); | 814 | (void) fprintf(el->el_errfile, "not found\n"); | |
814 | #endif | 815 | #endif | |
815 | return CC_ERROR; | 816 | return CC_ERROR; | |
816 | } | 817 | } | |
817 | } | 818 | } | |
818 | el->el_history.eventno = found; | 819 | el->el_history.eventno = found; | |
819 | 820 | |||
820 | return hist_get(el); | 821 | return hist_get(el); | |
821 | } | 822 | } | |
822 | 823 | |||
823 | 824 | |||
824 | /* ed_prev_line(): | 825 | /* ed_prev_line(): | |
825 | * Move up one line | 826 | * Move up one line | |
826 | * Could be [k] [^p] | 827 | * Could be [k] [^p] | |
827 | */ | 828 | */ | |
828 | protected el_action_t | 829 | protected el_action_t | |
829 | /*ARGSUSED*/ | 830 | /*ARGSUSED*/ | |
830 | ed_prev_line(EditLine *el, Int c __attribute__((__unused__))) | 831 | ed_prev_line(EditLine *el, Int c __attribute__((__unused__))) | |
831 | { | 832 | { | |
832 | Char *ptr; | 833 | Char *ptr; | |
833 | int nchars = c_hpos(el); | 834 | int nchars = c_hpos(el); | |
834 | 835 | |||
835 | /* | 836 | /* | |
836 | * Move to the line requested | 837 | * Move to the line requested | |
837 | */ | 838 | */ | |
838 | if (*(ptr = el->el_line.cursor) == '\n') | 839 | if (*(ptr = el->el_line.cursor) == '\n') | |
839 | ptr--; | 840 | ptr--; | |
840 | 841 | |||
841 | for (; ptr >= el->el_line.buffer; ptr--) | 842 | for (; ptr >= el->el_line.buffer; ptr--) | |
842 | if (*ptr == '\n' && --el->el_state.argument <= 0) | 843 | if (*ptr == '\n' && --el->el_state.argument <= 0) | |
843 | break; | 844 | break; | |
844 | 845 | |||
845 | if (el->el_state.argument > 0) | 846 | if (el->el_state.argument > 0) | |
846 | return CC_ERROR; | 847 | return CC_ERROR; | |
847 | 848 | |||
848 | /* | 849 | /* | |
849 | * Move to the beginning of the line | 850 | * Move to the beginning of the line | |
850 | */ | 851 | */ | |
851 | for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--) | 852 | for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--) | |
852 | continue; | 853 | continue; | |
853 | 854 | |||
854 | /* | 855 | /* | |
855 | * Move to the character requested | 856 | * Move to the character requested | |
856 | */ | 857 | */ | |
857 | for (ptr++; | 858 | for (ptr++; | |
858 | nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n'; | 859 | nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n'; | |
859 | ptr++) | 860 | ptr++) | |
860 | continue; | 861 | continue; | |
861 | 862 | |||
862 | el->el_line.cursor = ptr; | 863 | el->el_line.cursor = ptr; | |
863 | return CC_CURSOR; | 864 | return CC_CURSOR; | |
864 | } | 865 | } | |
865 | 866 | |||
866 | 867 | |||
867 | /* ed_next_line(): | 868 | /* ed_next_line(): | |
868 | * Move down one line | 869 | * Move down one line | |
869 | * Could be [j] [^n] | 870 | * Could be [j] [^n] | |
870 | */ | 871 | */ | |
871 | protected el_action_t | 872 | protected el_action_t | |
872 | /*ARGSUSED*/ | 873 | /*ARGSUSED*/ | |
873 | ed_next_line(EditLine *el, Int c __attribute__((__unused__))) | 874 | ed_next_line(EditLine *el, Int c __attribute__((__unused__))) | |
874 | { | 875 | { | |
875 | Char *ptr; | 876 | Char *ptr; | |
876 | int nchars = c_hpos(el); | 877 | int nchars = c_hpos(el); | |
877 | 878 | |||
878 | /* | 879 | /* | |
879 | * Move to the line requested | 880 | * Move to the line requested | |
880 | */ | 881 | */ | |
881 | for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++) | 882 | for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++) | |
882 | if (*ptr == '\n' && --el->el_state.argument <= 0) | 883 | if (*ptr == '\n' && --el->el_state.argument <= 0) | |
883 | break; | 884 | break; | |
884 | 885 | |||
885 | if (el->el_state.argument > 0) | 886 | if (el->el_state.argument > 0) | |
886 | return CC_ERROR; | 887 | return CC_ERROR; | |
887 | 888 | |||
888 | /* | 889 | /* | |
889 | * Move to the character requested | 890 | * Move to the character requested | |
890 | */ | 891 | */ | |
891 | for (ptr++; | 892 | for (ptr++; | |
892 | nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n'; | 893 | nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n'; | |
893 | ptr++) | 894 | ptr++) | |
894 | continue; | 895 | continue; | |
895 | 896 | |||
896 | el->el_line.cursor = ptr; | 897 | el->el_line.cursor = ptr; | |
897 | return CC_CURSOR; | 898 | return CC_CURSOR; | |
898 | } | 899 | } | |
899 | 900 | |||
900 | 901 | |||
901 | /* ed_command(): | 902 | /* ed_command(): | |
902 | * Editline extended command | 903 | * Editline extended command | |
903 | * [M-X] [:] | 904 | * [M-X] [:] | |
904 | */ | 905 | */ | |
905 | protected el_action_t | 906 | protected el_action_t | |
906 | /*ARGSUSED*/ | 907 | /*ARGSUSED*/ | |
907 | ed_command(EditLine *el, Int c __attribute__((__unused__))) | 908 | ed_command(EditLine *el, Int c __attribute__((__unused__))) | |
908 | { | 909 | { | |
909 | Char tmpbuf[EL_BUFSIZ]; | 910 | Char tmpbuf[EL_BUFSIZ]; | |
910 | int tmplen; | 911 | int tmplen; | |
911 | 912 | |||
912 | tmplen = c_gets(el, tmpbuf, STR("\n: ")); | 913 | tmplen = c_gets(el, tmpbuf, STR("\n: ")); | |
913 | terminal__putc(el, '\n'); | 914 | terminal__putc(el, '\n'); | |
914 | 915 | |||
915 | if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1) | 916 | if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1) | |
916 | terminal_beep(el); | 917 | terminal_beep(el); | |
917 | 918 | |||
918 | el->el_map.current = el->el_map.key; | 919 | el->el_map.current = el->el_map.key; | |
919 | re_clear_display(el); | 920 | re_clear_display(el); | |
920 | return CC_REFRESH; | 921 | return CC_REFRESH; | |
921 | } | 922 | } |
--- src/lib/libedit/filecomplete.c 2011/07/29 15:16:33 1.27
+++ src/lib/libedit/filecomplete.c 2011/07/29 20:58:07 1.28
@@ -1,581 +1,577 @@ | @@ -1,581 +1,577 @@ | |||
1 | /* $NetBSD: filecomplete.c,v 1.27 2011/07/29 15:16:33 christos Exp $ */ | 1 | /* $NetBSD: filecomplete.c,v 1.28 2011/07/29 20:58:07 christos Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Jaromir Dolecek. | 8 | * by Jaromir Dolecek. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include "config.h" | 32 | #include "config.h" | |
33 | #if !defined(lint) && !defined(SCCSID) | 33 | #if !defined(lint) && !defined(SCCSID) | |
34 | __RCSID("$NetBSD: filecomplete.c,v 1.27 2011/07/29 15:16:33 christos Exp $"); | 34 | __RCSID("$NetBSD: filecomplete.c,v 1.28 2011/07/29 20:58:07 christos Exp $"); | |
35 | #endif /* not lint && not SCCSID */ | 35 | #endif /* not lint && not SCCSID */ | |
36 | 36 | |||
37 | #include <sys/types.h> | 37 | #include <sys/types.h> | |
38 | #include <sys/stat.h> | 38 | #include <sys/stat.h> | |
39 | #include <stdio.h> | 39 | #include <stdio.h> | |
40 | #include <dirent.h> | 40 | #include <dirent.h> | |
41 | #include <string.h> | 41 | #include <string.h> | |
42 | #include <pwd.h> | 42 | #include <pwd.h> | |
43 | #include <ctype.h> | 43 | #include <ctype.h> | |
44 | #include <stdlib.h> | 44 | #include <stdlib.h> | |
45 | #include <unistd.h> | 45 | #include <unistd.h> | |
46 | #include <limits.h> | 46 | #include <limits.h> | |
47 | #include <errno.h> | 47 | #include <errno.h> | |
48 | #include <fcntl.h> | 48 | #include <fcntl.h> | |
49 | #ifdef HAVE_VIS_H | 49 | ||
50 | #include <vis.h> | |||
51 | #else | |||
52 | #include "vis.h" | |||
53 | #endif | |||
54 | #include "el.h" | 50 | #include "el.h" | |
55 | #include "fcns.h" /* for EL_NUM_FCNS */ | 51 | #include "fcns.h" /* for EL_NUM_FCNS */ | |
56 | #include "histedit.h" | 52 | #include "histedit.h" | |
57 | #include "filecomplete.h" | 53 | #include "filecomplete.h" | |
58 | 54 | |||
59 | static const Char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', | 55 | static const Char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', | |
60 | '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; | 56 | '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; | |
61 | 57 | |||
62 | 58 | |||
63 | /********************************/ | 59 | /********************************/ | |
64 | /* completion functions */ | 60 | /* completion functions */ | |
65 | 61 | |||
66 | /* | 62 | /* | |
67 | * does tilde expansion of strings of type ``~user/foo'' | 63 | * does tilde expansion of strings of type ``~user/foo'' | |
68 | * if ``user'' isn't valid user name or ``txt'' doesn't start | 64 | * if ``user'' isn't valid user name or ``txt'' doesn't start | |
69 | * w/ '~', returns pointer to strdup()ed copy of ``txt'' | 65 | * w/ '~', returns pointer to strdup()ed copy of ``txt'' | |
70 | * | 66 | * | |
71 | * it's callers's responsibility to free() returned string | 67 | * it's callers's responsibility to free() returned string | |
72 | */ | 68 | */ | |
73 | char * | 69 | char * | |
74 | fn_tilde_expand(const char *txt) | 70 | fn_tilde_expand(const char *txt) | |
75 | { | 71 | { | |
76 | #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) | 72 | #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) | |
77 | struct passwd pwres; | 73 | struct passwd pwres; | |
78 | char pwbuf[1024]; | 74 | char pwbuf[1024]; | |
79 | #endif | 75 | #endif | |
80 | struct passwd *pass; | 76 | struct passwd *pass; | |
81 | char *temp; | 77 | char *temp; | |
82 | size_t len = 0; | 78 | size_t len = 0; | |
83 | 79 | |||
84 | if (txt[0] != '~') | 80 | if (txt[0] != '~') | |
85 | return strdup(txt); | 81 | return strdup(txt); | |
86 | 82 | |||
87 | temp = strchr(txt + 1, '/'); | 83 | temp = strchr(txt + 1, '/'); | |
88 | if (temp == NULL) { | 84 | if (temp == NULL) { | |
89 | temp = strdup(txt + 1); | 85 | temp = strdup(txt + 1); | |
90 | if (temp == NULL) | 86 | if (temp == NULL) | |
91 | return NULL; | 87 | return NULL; | |
92 | } else { | 88 | } else { | |
93 | len = temp - txt + 1; /* text until string after slash */ | 89 | len = temp - txt + 1; /* text until string after slash */ | |
94 | temp = el_malloc(len * sizeof(*temp)); | 90 | temp = el_malloc(len * sizeof(*temp)); | |
95 | if (temp == NULL) | 91 | if (temp == NULL) | |
96 | return NULL; | 92 | return NULL; | |
97 | (void)strncpy(temp, txt + 1, len - 2); | 93 | (void)strncpy(temp, txt + 1, len - 2); | |
98 | temp[len - 2] = '\0'; | 94 | temp[len - 2] = '\0'; | |
99 | } | 95 | } | |
100 | if (temp[0] == 0) { | 96 | if (temp[0] == 0) { | |
101 | #ifdef HAVE_GETPW_R_POSIX | 97 | #ifdef HAVE_GETPW_R_POSIX | |
102 | if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), | 98 | if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), | |
103 | &pass) != 0) | 99 | &pass) != 0) | |
104 | pass = NULL; | 100 | pass = NULL; | |
105 | #elif HAVE_GETPW_R_DRAFT | 101 | #elif HAVE_GETPW_R_DRAFT | |
106 | pass = getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf)); | 102 | pass = getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf)); | |
107 | #else | 103 | #else | |
108 | pass = getpwuid(getuid()); | 104 | pass = getpwuid(getuid()); | |
109 | #endif | 105 | #endif | |
110 | } else { | 106 | } else { | |
111 | #ifdef HAVE_GETPW_R_POSIX | 107 | #ifdef HAVE_GETPW_R_POSIX | |
112 | if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) | 108 | if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) | |
113 | pass = NULL; | 109 | pass = NULL; | |
114 | #elif HAVE_GETPW_R_DRAFT | 110 | #elif HAVE_GETPW_R_DRAFT | |
115 | pass = getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf)); | 111 | pass = getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf)); | |
116 | #else | 112 | #else | |
117 | pass = getpwnam(temp); | 113 | pass = getpwnam(temp); | |
118 | #endif | 114 | #endif | |
119 | } | 115 | } | |
120 | el_free(temp); /* value no more needed */ | 116 | el_free(temp); /* value no more needed */ | |
121 | if (pass == NULL) | 117 | if (pass == NULL) | |
122 | return strdup(txt); | 118 | return strdup(txt); | |
123 | 119 | |||
124 | /* update pointer txt to point at string immedially following */ | 120 | /* update pointer txt to point at string immedially following */ | |
125 | /* first slash */ | 121 | /* first slash */ | |
126 | txt += len; | 122 | txt += len; | |
127 | 123 | |||
128 | len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1; | 124 | len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1; | |
129 | temp = el_malloc(len * sizeof(*temp)); | 125 | temp = el_malloc(len * sizeof(*temp)); | |
130 | if (temp == NULL) | 126 | if (temp == NULL) | |
131 | return NULL; | 127 | return NULL; | |
132 | (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt); | 128 | (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt); | |
133 | 129 | |||
134 | return temp; | 130 | return temp; | |
135 | } | 131 | } | |
136 | 132 | |||
137 | 133 | |||
138 | /* | 134 | /* | |
139 | * return first found file name starting by the ``text'' or NULL if no | 135 | * return first found file name starting by the ``text'' or NULL if no | |
140 | * such file can be found | 136 | * such file can be found | |
141 | * value of ``state'' is ignored | 137 | * value of ``state'' is ignored | |
142 | * | 138 | * | |
143 | * it's caller's responsibility to free returned string | 139 | * it's caller's responsibility to free returned string | |
144 | */ | 140 | */ | |
145 | char * | 141 | char * | |
146 | fn_filename_completion_function(const char *text, int state) | 142 | fn_filename_completion_function(const char *text, int state) | |
147 | { | 143 | { | |
148 | static DIR *dir = NULL; | 144 | static DIR *dir = NULL; | |
149 | static char *filename = NULL, *dirname = NULL, *dirpath = NULL; | 145 | static char *filename = NULL, *dirname = NULL, *dirpath = NULL; | |
150 | static size_t filename_len = 0; | 146 | static size_t filename_len = 0; | |
151 | struct dirent *entry; | 147 | struct dirent *entry; | |
152 | char *temp; | 148 | char *temp; | |
153 | size_t len; | 149 | size_t len; | |
154 | 150 | |||
155 | if (state == 0 || dir == NULL) { | 151 | if (state == 0 || dir == NULL) { | |
156 | temp = strrchr(text, '/'); | 152 | temp = strrchr(text, '/'); | |
157 | if (temp) { | 153 | if (temp) { | |
158 | char *nptr; | 154 | char *nptr; | |
159 | temp++; | 155 | temp++; | |
160 | nptr = el_realloc(filename, (strlen(temp) + 1) * | 156 | nptr = el_realloc(filename, (strlen(temp) + 1) * | |
161 | sizeof(*nptr)); | 157 | sizeof(*nptr)); | |
162 | if (nptr == NULL) { | 158 | if (nptr == NULL) { | |
163 | el_free(filename); | 159 | el_free(filename); | |
164 | filename = NULL; | 160 | filename = NULL; | |
165 | return NULL; | 161 | return NULL; | |
166 | } | 162 | } | |
167 | filename = nptr; | 163 | filename = nptr; | |
168 | (void)strcpy(filename, temp); | 164 | (void)strcpy(filename, temp); | |
169 | len = temp - text; /* including last slash */ | 165 | len = temp - text; /* including last slash */ | |
170 | 166 | |||
171 | nptr = el_realloc(dirname, (len + 1) * | 167 | nptr = el_realloc(dirname, (len + 1) * | |
172 | sizeof(*nptr)); | 168 | sizeof(*nptr)); | |
173 | if (nptr == NULL) { | 169 | if (nptr == NULL) { | |
174 | el_free(dirname); | 170 | el_free(dirname); | |
175 | dirname = NULL; | 171 | dirname = NULL; | |
176 | return NULL; | 172 | return NULL; | |
177 | } | 173 | } | |
178 | dirname = nptr; | 174 | dirname = nptr; | |
179 | (void)strncpy(dirname, text, len); | 175 | (void)strncpy(dirname, text, len); | |
180 | dirname[len] = '\0'; | 176 | dirname[len] = '\0'; | |
181 | } else { | 177 | } else { | |
182 | el_free(filename); | 178 | el_free(filename); | |
183 | if (*text == 0) | 179 | if (*text == 0) | |
184 | filename = NULL; | 180 | filename = NULL; | |
185 | else { | 181 | else { | |
186 | filename = strdup(text); | 182 | filename = strdup(text); | |
187 | if (filename == NULL) | 183 | if (filename == NULL) | |
188 | return NULL; | 184 | return NULL; | |
189 | } | 185 | } | |
190 | el_free(dirname); | 186 | el_free(dirname); | |
191 | dirname = NULL; | 187 | dirname = NULL; | |
192 | } | 188 | } | |
193 | 189 | |||
194 | if (dir != NULL) { | 190 | if (dir != NULL) { | |
195 | (void)closedir(dir); | 191 | (void)closedir(dir); | |
196 | dir = NULL; | 192 | dir = NULL; | |
197 | } | 193 | } | |
198 | 194 | |||
199 | /* support for ``~user'' syntax */ | 195 | /* support for ``~user'' syntax */ | |
200 | 196 | |||
201 | el_free(dirpath); | 197 | el_free(dirpath); | |
202 | dirpath = NULL; | 198 | dirpath = NULL; | |
203 | if (dirname == NULL) { | 199 | if (dirname == NULL) { | |
204 | if ((dirname = strdup("")) == NULL) | 200 | if ((dirname = strdup("")) == NULL) | |
205 | return NULL; | 201 | return NULL; | |
206 | dirpath = strdup("./"); | 202 | dirpath = strdup("./"); | |
207 | } else if (*dirname == '~') | 203 | } else if (*dirname == '~') | |
208 | dirpath = fn_tilde_expand(dirname); | 204 | dirpath = fn_tilde_expand(dirname); | |
209 | else | 205 | else | |
210 | dirpath = strdup(dirname); | 206 | dirpath = strdup(dirname); | |
211 | 207 | |||
212 | if (dirpath == NULL) | 208 | if (dirpath == NULL) | |
213 | return NULL; | 209 | return NULL; | |
214 | 210 | |||
215 | dir = opendir(dirpath); | 211 | dir = opendir(dirpath); | |
216 | if (!dir) | 212 | if (!dir) | |
217 | return NULL; /* cannot open the directory */ | 213 | return NULL; /* cannot open the directory */ | |
218 | 214 | |||
219 | /* will be used in cycle */ | 215 | /* will be used in cycle */ | |
220 | filename_len = filename ? strlen(filename) : 0; | 216 | filename_len = filename ? strlen(filename) : 0; | |
221 | } | 217 | } | |
222 | 218 | |||
223 | /* find the match */ | 219 | /* find the match */ | |
224 | while ((entry = readdir(dir)) != NULL) { | 220 | while ((entry = readdir(dir)) != NULL) { | |
225 | /* skip . and .. */ | 221 | /* skip . and .. */ | |
226 | if (entry->d_name[0] == '.' && (!entry->d_name[1] | 222 | if (entry->d_name[0] == '.' && (!entry->d_name[1] | |
227 | || (entry->d_name[1] == '.' && !entry->d_name[2]))) | 223 | || (entry->d_name[1] == '.' && !entry->d_name[2]))) | |
228 | continue; | 224 | continue; | |
229 | if (filename_len == 0) | 225 | if (filename_len == 0) | |
230 | break; | 226 | break; | |
231 | /* otherwise, get first entry where first */ | 227 | /* otherwise, get first entry where first */ | |
232 | /* filename_len characters are equal */ | 228 | /* filename_len characters are equal */ | |
233 | if (entry->d_name[0] == filename[0] | 229 | if (entry->d_name[0] == filename[0] | |
234 | #if HAVE_STRUCT_DIRENT_D_NAMLEN | 230 | #if HAVE_STRUCT_DIRENT_D_NAMLEN | |
235 | && entry->d_namlen >= filename_len | 231 | && entry->d_namlen >= filename_len | |
236 | #else | 232 | #else | |
237 | && strlen(entry->d_name) >= filename_len | 233 | && strlen(entry->d_name) >= filename_len | |
238 | #endif | 234 | #endif | |
239 | && strncmp(entry->d_name, filename, | 235 | && strncmp(entry->d_name, filename, | |
240 | filename_len) == 0) | 236 | filename_len) == 0) | |
241 | break; | 237 | break; | |
242 | } | 238 | } | |
243 | 239 | |||
244 | if (entry) { /* match found */ | 240 | if (entry) { /* match found */ | |
245 | 241 | |||
246 | #if HAVE_STRUCT_DIRENT_D_NAMLEN | 242 | #if HAVE_STRUCT_DIRENT_D_NAMLEN | |
247 | len = entry->d_namlen; | 243 | len = entry->d_namlen; | |
248 | #else | 244 | #else | |
249 | len = strlen(entry->d_name); | 245 | len = strlen(entry->d_name); | |
250 | #endif | 246 | #endif | |
251 | 247 | |||
252 | len = strlen(dirname) + len + 1; | 248 | len = strlen(dirname) + len + 1; | |
253 | temp = el_malloc(len * sizeof(*temp)); | 249 | temp = el_malloc(len * sizeof(*temp)); | |
254 | if (temp == NULL) | 250 | if (temp == NULL) | |
255 | return NULL; | 251 | return NULL; | |
256 | (void)snprintf(temp, len, "%s%s", dirname, entry->d_name); | 252 | (void)snprintf(temp, len, "%s%s", dirname, entry->d_name); | |
257 | } else { | 253 | } else { | |
258 | (void)closedir(dir); | 254 | (void)closedir(dir); | |
259 | dir = NULL; | 255 | dir = NULL; | |
260 | temp = NULL; | 256 | temp = NULL; | |
261 | } | 257 | } | |
262 | 258 | |||
263 | return temp; | 259 | return temp; | |
264 | } | 260 | } | |
265 | 261 | |||
266 | 262 | |||
267 | static const char * | 263 | static const char * | |
268 | append_char_function(const char *name) | 264 | append_char_function(const char *name) | |
269 | { | 265 | { | |
270 | struct stat stbuf; | 266 | struct stat stbuf; | |
271 | char *expname = *name == '~' ? fn_tilde_expand(name) : NULL; | 267 | char *expname = *name == '~' ? fn_tilde_expand(name) : NULL; | |
272 | const char *rs = " "; | 268 | const char *rs = " "; | |
273 | 269 | |||
274 | if (stat(expname ? expname : name, &stbuf) == -1) | 270 | if (stat(expname ? expname : name, &stbuf) == -1) | |
275 | goto out; | 271 | goto out; | |
276 | if (S_ISDIR(stbuf.st_mode)) | 272 | if (S_ISDIR(stbuf.st_mode)) | |
277 | rs = "/"; | 273 | rs = "/"; | |
278 | out: | 274 | out: | |
279 | if (expname) | 275 | if (expname) | |
280 | el_free(expname); | 276 | el_free(expname); | |
281 | return rs; | 277 | return rs; | |
282 | } | 278 | } | |
283 | /* | 279 | /* | |
284 | * returns list of completions for text given | 280 | * returns list of completions for text given | |
285 | * non-static for readline. | 281 | * non-static for readline. | |
286 | */ | 282 | */ | |
287 | char ** completion_matches(const char *, char *(*)(const char *, int)); | 283 | char ** completion_matches(const char *, char *(*)(const char *, int)); | |
288 | char ** | 284 | char ** | |
289 | completion_matches(const char *text, char *(*genfunc)(const char *, int)) | 285 | completion_matches(const char *text, char *(*genfunc)(const char *, int)) | |
290 | { | 286 | { | |
291 | char **match_list = NULL, *retstr, *prevstr; | 287 | char **match_list = NULL, *retstr, *prevstr; | |
292 | size_t match_list_len, max_equal, which, i; | 288 | size_t match_list_len, max_equal, which, i; | |
293 | size_t matches; | 289 | size_t matches; | |
294 | 290 | |||
295 | matches = 0; | 291 | matches = 0; | |
296 | match_list_len = 1; | 292 | match_list_len = 1; | |
297 | while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { | 293 | while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { | |
298 | /* allow for list terminator here */ | 294 | /* allow for list terminator here */ | |
299 | if (matches + 3 >= match_list_len) { | 295 | if (matches + 3 >= match_list_len) { | |
300 | char **nmatch_list; | 296 | char **nmatch_list; | |
301 | while (matches + 3 >= match_list_len) | 297 | while (matches + 3 >= match_list_len) | |
302 | match_list_len <<= 1; | 298 | match_list_len <<= 1; | |
303 | nmatch_list = el_realloc(match_list, | 299 | nmatch_list = el_realloc(match_list, | |
304 | match_list_len * sizeof(*nmatch_list)); | 300 | match_list_len * sizeof(*nmatch_list)); | |
305 | if (nmatch_list == NULL) { | 301 | if (nmatch_list == NULL) { | |
306 | el_free(match_list); | 302 | el_free(match_list); | |
307 | return NULL; | 303 | return NULL; | |
308 | } | 304 | } | |
309 | match_list = nmatch_list; | 305 | match_list = nmatch_list; | |
310 | 306 | |||
311 | } | 307 | } | |
312 | match_list[++matches] = retstr; | 308 | match_list[++matches] = retstr; | |
313 | } | 309 | } | |
314 | 310 | |||
315 | if (!match_list) | 311 | if (!match_list) | |
316 | return NULL; /* nothing found */ | 312 | return NULL; /* nothing found */ | |
317 | 313 | |||
318 | /* find least denominator and insert it to match_list[0] */ | 314 | /* find least denominator and insert it to match_list[0] */ | |
319 | which = 2; | 315 | which = 2; | |
320 | prevstr = match_list[1]; | 316 | prevstr = match_list[1]; | |
321 | max_equal = strlen(prevstr); | 317 | max_equal = strlen(prevstr); | |
322 | for (; which <= matches; which++) { | 318 | for (; which <= matches; which++) { | |
323 | for (i = 0; i < max_equal && | 319 | for (i = 0; i < max_equal && | |
324 | prevstr[i] == match_list[which][i]; i++) | 320 | prevstr[i] == match_list[which][i]; i++) | |
325 | continue; | 321 | continue; | |
326 | max_equal = i; | 322 | max_equal = i; | |
327 | } | 323 | } | |
328 | 324 | |||
329 | retstr = el_malloc((max_equal + 1) * sizeof(*retstr)); | 325 | retstr = el_malloc((max_equal + 1) * sizeof(*retstr)); | |
330 | if (retstr == NULL) { | 326 | if (retstr == NULL) { | |
331 | el_free(match_list); | 327 | el_free(match_list); | |
332 | return NULL; | 328 | return NULL; | |
333 | } | 329 | } | |
334 | (void)strncpy(retstr, match_list[1], max_equal); | 330 | (void)strncpy(retstr, match_list[1], max_equal); | |
335 | retstr[max_equal] = '\0'; | 331 | retstr[max_equal] = '\0'; | |
336 | match_list[0] = retstr; | 332 | match_list[0] = retstr; | |
337 | 333 | |||
338 | /* add NULL as last pointer to the array */ | 334 | /* add NULL as last pointer to the array */ | |
339 | match_list[matches + 1] = (char *) NULL; | 335 | match_list[matches + 1] = (char *) NULL; | |
340 | 336 | |||
341 | return match_list; | 337 | return match_list; | |
342 | } | 338 | } | |
343 | 339 | |||
344 | /* | 340 | /* | |
345 | * Sort function for qsort(). Just wrapper around strcasecmp(). | 341 | * Sort function for qsort(). Just wrapper around strcasecmp(). | |
346 | */ | 342 | */ | |
347 | static int | 343 | static int | |
348 | _fn_qsort_string_compare(const void *i1, const void *i2) | 344 | _fn_qsort_string_compare(const void *i1, const void *i2) | |
349 | { | 345 | { | |
350 | const char *s1 = ((const char * const *)i1)[0]; | 346 | const char *s1 = ((const char * const *)i1)[0]; | |
351 | const char *s2 = ((const char * const *)i2)[0]; | 347 | const char *s2 = ((const char * const *)i2)[0]; | |
352 | 348 | |||
353 | return strcasecmp(s1, s2); | 349 | return strcasecmp(s1, s2); | |
354 | } | 350 | } | |
355 | 351 | |||
356 | /* | 352 | /* | |
357 | * Display list of strings in columnar format on readline's output stream. | 353 | * Display list of strings in columnar format on readline's output stream. | |
358 | * 'matches' is list of strings, 'num' is number of strings in 'matches', | 354 | * 'matches' is list of strings, 'num' is number of strings in 'matches', | |
359 | * 'width' is maximum length of string in 'matches'. | 355 | * 'width' is maximum length of string in 'matches'. | |
360 | * | 356 | * | |
361 | * matches[0] is not one of the match strings, but it is counted in | 357 | * matches[0] is not one of the match strings, but it is counted in | |
362 | * num, so the strings are matches[1] *through* matches[num-1]. | 358 | * num, so the strings are matches[1] *through* matches[num-1]. | |
363 | */ | 359 | */ | |
364 | void | 360 | void | |
365 | fn_display_match_list (EditLine *el, char **matches, size_t num, size_t width) | 361 | fn_display_match_list (EditLine *el, char **matches, size_t num, size_t width) | |
366 | { | 362 | { | |
367 | size_t line, lines, col, cols, thisguy; | 363 | size_t line, lines, col, cols, thisguy; | |
368 | int screenwidth = el->el_terminal.t_size.h; | 364 | int screenwidth = el->el_terminal.t_size.h; | |
369 | 365 | |||
370 | /* Ignore matches[0]. Avoid 1-based array logic below. */ | 366 | /* Ignore matches[0]. Avoid 1-based array logic below. */ | |
371 | matches++; | 367 | matches++; | |
372 | num--; | 368 | num--; | |
373 | 369 | |||
374 | /* | 370 | /* | |
375 | * Find out how many entries can be put on one line; count | 371 | * Find out how many entries can be put on one line; count | |
376 | * with one space between strings the same way it's printed. | 372 | * with one space between strings the same way it's printed. | |
377 | */ | 373 | */ | |
378 | cols = screenwidth / (width + 1); | 374 | cols = screenwidth / (width + 1); | |
379 | if (cols == 0) | 375 | if (cols == 0) | |
380 | cols = 1; | 376 | cols = 1; | |
381 | 377 | |||
382 | /* how many lines of output, rounded up */ | 378 | /* how many lines of output, rounded up */ | |
383 | lines = (num + cols - 1) / cols; | 379 | lines = (num + cols - 1) / cols; | |
384 | 380 | |||
385 | /* Sort the items. */ | 381 | /* Sort the items. */ | |
386 | qsort(matches, num, sizeof(char *), _fn_qsort_string_compare); | 382 | qsort(matches, num, sizeof(char *), _fn_qsort_string_compare); | |
387 | 383 | |||
388 | /* | 384 | /* | |
389 | * On the ith line print elements i, i+lines, i+lines*2, etc. | 385 | * On the ith line print elements i, i+lines, i+lines*2, etc. | |
390 | */ | 386 | */ | |
391 | for (line = 0; line < lines; line++) { | 387 | for (line = 0; line < lines; line++) { | |
392 | for (col = 0; col < cols; col++) { | 388 | for (col = 0; col < cols; col++) { | |
393 | thisguy = line + col * lines; | 389 | thisguy = line + col * lines; | |
394 | if (thisguy >= num) | 390 | if (thisguy >= num) | |
395 | break; | 391 | break; | |
396 | (void)fprintf(el->el_outfile, "%s%-*s", | 392 | (void)fprintf(el->el_outfile, "%s%-*s", | |
397 | col == 0 ? "" : " ", (int)width, matches[thisguy]); | 393 | col == 0 ? "" : " ", (int)width, matches[thisguy]); | |
398 | } | 394 | } | |
399 | (void)fprintf(el->el_outfile, "\n"); | 395 | (void)fprintf(el->el_outfile, "\n"); | |
400 | } | 396 | } | |
401 | } | 397 | } | |
402 | 398 | |||
403 | /* | 399 | /* | |
404 | * Complete the word at or before point, | 400 | * Complete the word at or before point, | |
405 | * 'what_to_do' says what to do with the completion. | 401 | * 'what_to_do' says what to do with the completion. | |
406 | * \t means do standard completion. | 402 | * \t means do standard completion. | |
407 | * `?' means list the possible completions. | 403 | * `?' means list the possible completions. | |
408 | * `*' means insert all of the possible completions. | 404 | * `*' means insert all of the possible completions. | |
409 | * `!' means to do standard completion, and list all possible completions if | 405 | * `!' means to do standard completion, and list all possible completions if | |
410 | * there is more than one. | 406 | * there is more than one. | |
411 | * | 407 | * | |
412 | * Note: '*' support is not implemented | 408 | * Note: '*' support is not implemented | |
413 | * '!' could never be invoked | 409 | * '!' could never be invoked | |
414 | */ | 410 | */ | |
415 | int | 411 | int | |
416 | fn_complete(EditLine *el, | 412 | fn_complete(EditLine *el, | |
417 | char *(*complet_func)(const char *, int), | 413 | char *(*complet_func)(const char *, int), | |
418 | char **(*attempted_completion_function)(const char *, int, int), | 414 | char **(*attempted_completion_function)(const char *, int, int), | |
419 | const Char *word_break, const Char *special_prefixes, | 415 | const Char *word_break, const Char *special_prefixes, | |
420 | const char *(*app_func)(const char *), size_t query_items, | 416 | const char *(*app_func)(const char *), size_t query_items, | |
421 | int *completion_type, int *over, int *point, int *end) | 417 | int *completion_type, int *over, int *point, int *end) | |
422 | { | 418 | { | |
423 | const TYPE(LineInfo) *li; | 419 | const TYPE(LineInfo) *li; | |
424 | Char *temp; | 420 | Char *temp; | |
425 | char **matches; | 421 | char **matches; | |
426 | const Char *ctemp; | 422 | const Char *ctemp; | |
427 | size_t len; | 423 | size_t len; | |
428 | int what_to_do = '\t'; | 424 | int what_to_do = '\t'; | |
429 | int retval = CC_NORM; | 425 | int retval = CC_NORM; | |
430 | 426 | |||
431 | if (el->el_state.lastcmd == el->el_state.thiscmd) | 427 | if (el->el_state.lastcmd == el->el_state.thiscmd) | |
432 | what_to_do = '?'; | 428 | what_to_do = '?'; | |
433 | 429 | |||
434 | /* readline's rl_complete() has to be told what we did... */ | 430 | /* readline's rl_complete() has to be told what we did... */ | |
435 | if (completion_type != NULL) | 431 | if (completion_type != NULL) | |
436 | *completion_type = what_to_do; | 432 | *completion_type = what_to_do; | |
437 | 433 | |||
438 | if (!complet_func) | 434 | if (!complet_func) | |
439 | complet_func = fn_filename_completion_function; | 435 | complet_func = fn_filename_completion_function; | |
440 | if (!app_func) | 436 | if (!app_func) | |
441 | app_func = append_char_function; | 437 | app_func = append_char_function; | |
442 | 438 | |||
443 | /* We now look backwards for the start of a filename/variable word */ | 439 | /* We now look backwards for the start of a filename/variable word */ | |
444 | li = FUN(el,line)(el); | 440 | li = FUN(el,line)(el); | |
445 | ctemp = li->cursor; | 441 | ctemp = li->cursor; | |
446 | while (ctemp > li->buffer | 442 | while (ctemp > li->buffer | |
447 | && !Strchr(word_break, ctemp[-1]) | 443 | && !Strchr(word_break, ctemp[-1]) | |
448 | && (!special_prefixes || !Strchr(special_prefixes, ctemp[-1]) ) ) | 444 | && (!special_prefixes || !Strchr(special_prefixes, ctemp[-1]) ) ) | |
449 | ctemp--; | 445 | ctemp--; | |
450 | 446 | |||
451 | len = li->cursor - ctemp; | 447 | len = li->cursor - ctemp; | |
452 | temp = el_malloc((len + 1) * sizeof(*temp)); | 448 | temp = el_malloc((len + 1) * sizeof(*temp)); | |
453 | (void)Strncpy(temp, ctemp, len); | 449 | (void)Strncpy(temp, ctemp, len); | |
454 | temp[len] = '\0'; | 450 | temp[len] = '\0'; | |
455 | 451 | |||
456 | /* these can be used by function called in completion_matches() */ | 452 | /* these can be used by function called in completion_matches() */ | |
457 | /* or (*attempted_completion_function)() */ | 453 | /* or (*attempted_completion_function)() */ | |
458 | if (point != 0) | 454 | if (point != 0) | |
459 | *point = (int)(li->cursor - li->buffer); | 455 | *point = (int)(li->cursor - li->buffer); | |
460 | if (end != NULL) | 456 | if (end != NULL) | |
461 | *end = (int)(li->lastchar - li->buffer); | 457 | *end = (int)(li->lastchar - li->buffer); | |
462 | 458 | |||
463 | if (attempted_completion_function) { | 459 | if (attempted_completion_function) { | |
464 | int cur_off = (int)(li->cursor - li->buffer); | 460 | int cur_off = (int)(li->cursor - li->buffer); | |
465 | matches = (*attempted_completion_function) (ct_encode_string(temp, &el->el_scratch), | 461 | matches = (*attempted_completion_function) (ct_encode_string(temp, &el->el_scratch), | |
466 | (int)(cur_off - len), cur_off); | 462 | (int)(cur_off - len), cur_off); | |
467 | } else | 463 | } else | |
468 | matches = 0; | 464 | matches = 0; | |
469 | if (!attempted_completion_function || | 465 | if (!attempted_completion_function || | |
470 | (over != NULL && !*over && !matches)) | 466 | (over != NULL && !*over && !matches)) | |
471 | matches = completion_matches(ct_encode_string(temp, &el->el_scratch), complet_func); | 467 | matches = completion_matches(ct_encode_string(temp, &el->el_scratch), complet_func); | |
472 | 468 | |||
473 | if (over != NULL) | 469 | if (over != NULL) | |
474 | *over = 0; | 470 | *over = 0; | |
475 | 471 | |||
476 | if (matches) { | 472 | if (matches) { | |
477 | int i; | 473 | int i; | |
478 | size_t matches_num, maxlen, match_len, match_display=1; | 474 | size_t matches_num, maxlen, match_len, match_display=1; | |
479 | 475 | |||
480 | retval = CC_REFRESH; | 476 | retval = CC_REFRESH; | |
481 | /* | 477 | /* | |
482 | * Only replace the completed string with common part of | 478 | * Only replace the completed string with common part of | |
483 | * possible matches if there is possible completion. | 479 | * possible matches if there is possible completion. | |
484 | */ | 480 | */ | |
485 | if (matches[0][0] != '\0') { | 481 | if (matches[0][0] != '\0') { | |
486 | el_deletestr(el, (int) len); | 482 | el_deletestr(el, (int) len); | |
487 | FUN(el,insertstr)(el, | 483 | FUN(el,insertstr)(el, | |
488 | ct_decode_string(matches[0], &el->el_scratch)); | 484 | ct_decode_string(matches[0], &el->el_scratch)); | |
489 | } | 485 | } | |
490 | 486 | |||
491 | if (what_to_do == '?') | 487 | if (what_to_do == '?') | |
492 | goto display_matches; | 488 | goto display_matches; | |
493 | 489 | |||
494 | if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { | 490 | if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { | |
495 | /* | 491 | /* | |
496 | * We found exact match. Add a space after | 492 | * We found exact match. Add a space after | |
497 | * it, unless we do filename completion and the | 493 | * it, unless we do filename completion and the | |
498 | * object is a directory. | 494 | * object is a directory. | |
499 | */ | 495 | */ | |
500 | FUN(el,insertstr)(el, | 496 | FUN(el,insertstr)(el, | |
501 | ct_decode_string((*app_func)(matches[0]), | 497 | ct_decode_string((*app_func)(matches[0]), | |
502 | &el->el_scratch)); | 498 | &el->el_scratch)); | |
503 | } else if (what_to_do == '!') { | 499 | } else if (what_to_do == '!') { | |
504 | display_matches: | 500 | display_matches: | |
505 | /* | 501 | /* | |
506 | * More than one match and requested to list possible | 502 | * More than one match and requested to list possible | |
507 | * matches. | 503 | * matches. | |
508 | */ | 504 | */ | |
509 | 505 | |||
510 | for(i = 1, maxlen = 0; matches[i]; i++) { | 506 | for(i = 1, maxlen = 0; matches[i]; i++) { | |
511 | match_len = strlen(matches[i]); | 507 | match_len = strlen(matches[i]); | |
512 | if (match_len > maxlen) | 508 | if (match_len > maxlen) | |
513 | maxlen = match_len; | 509 | maxlen = match_len; | |
514 | } | 510 | } | |
515 | /* matches[1] through matches[i-1] are available */ | 511 | /* matches[1] through matches[i-1] are available */ | |
516 | matches_num = i - 1; | 512 | matches_num = i - 1; | |
517 | 513 | |||
518 | /* newline to get on next line from command line */ | 514 | /* newline to get on next line from command line */ | |
519 | (void)fprintf(el->el_outfile, "\n"); | 515 | (void)fprintf(el->el_outfile, "\n"); | |
520 | 516 | |||
521 | /* | 517 | /* | |
522 | * If there are too many items, ask user for display | 518 | * If there are too many items, ask user for display | |
523 | * confirmation. | 519 | * confirmation. | |
524 | */ | 520 | */ | |
525 | if (matches_num > query_items) { | 521 | if (matches_num > query_items) { | |
526 | (void)fprintf(el->el_outfile, | 522 | (void)fprintf(el->el_outfile, | |
527 | "Display all %zu possibilities? (y or n) ", | 523 | "Display all %zu possibilities? (y or n) ", | |
528 | matches_num); | 524 | matches_num); | |
529 | (void)fflush(el->el_outfile); | 525 | (void)fflush(el->el_outfile); | |
530 | if (getc(stdin) != 'y') | 526 | if (getc(stdin) != 'y') | |
531 | match_display = 0; | 527 | match_display = 0; | |
532 | (void)fprintf(el->el_outfile, "\n"); | 528 | (void)fprintf(el->el_outfile, "\n"); | |
533 | } | 529 | } | |
534 | 530 | |||
535 | if (match_display) { | 531 | if (match_display) { | |
536 | /* | 532 | /* | |
537 | * Interface of this function requires the | 533 | * Interface of this function requires the | |
538 | * strings be matches[1..num-1] for compat. | 534 | * strings be matches[1..num-1] for compat. | |
539 | * We have matches_num strings not counting | 535 | * We have matches_num strings not counting | |
540 | * the prefix in matches[0], so we need to | 536 | * the prefix in matches[0], so we need to | |
541 | * add 1 to matches_num for the call. | 537 | * add 1 to matches_num for the call. | |
542 | */ | 538 | */ | |
543 | fn_display_match_list(el, matches, | 539 | fn_display_match_list(el, matches, | |
544 | matches_num+1, maxlen); | 540 | matches_num+1, maxlen); | |
545 | } | 541 | } | |
546 | retval = CC_REDISPLAY; | 542 | retval = CC_REDISPLAY; | |
547 | } else if (matches[0][0]) { | 543 | } else if (matches[0][0]) { | |
548 | /* | 544 | /* | |
549 | * There was some common match, but the name was | 545 | * There was some common match, but the name was | |
550 | * not complete enough. Next tab will print possible | 546 | * not complete enough. Next tab will print possible | |
551 | * completions. | 547 | * completions. | |
552 | */ | 548 | */ | |
553 | el_beep(el); | 549 | el_beep(el); | |
554 | } else { | 550 | } else { | |
555 | /* lcd is not a valid object - further specification */ | 551 | /* lcd is not a valid object - further specification */ | |
556 | /* is needed */ | 552 | /* is needed */ | |
557 | el_beep(el); | 553 | el_beep(el); | |
558 | retval = CC_NORM; | 554 | retval = CC_NORM; | |
559 | } | 555 | } | |
560 | 556 | |||
561 | /* free elements of array and the array itself */ | 557 | /* free elements of array and the array itself */ | |
562 | for (i = 0; matches[i]; i++) | 558 | for (i = 0; matches[i]; i++) | |
563 | el_free(matches[i]); | 559 | el_free(matches[i]); | |
564 | el_free(matches); | 560 | el_free(matches); | |
565 | matches = NULL; | 561 | matches = NULL; | |
566 | } | 562 | } | |
567 | el_free(temp); | 563 | el_free(temp); | |
568 | return retval; | 564 | return retval; | |
569 | } | 565 | } | |
570 | 566 | |||
571 | /* | 567 | /* | |
572 | * el-compatible wrapper around rl_complete; needed for key binding | 568 | * el-compatible wrapper around rl_complete; needed for key binding | |
573 | */ | 569 | */ | |
574 | /* ARGSUSED */ | 570 | /* ARGSUSED */ | |
575 | unsigned char | 571 | unsigned char | |
576 | _el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) | 572 | _el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) | |
577 | { | 573 | { | |
578 | return (unsigned char)fn_complete(el, NULL, NULL, | 574 | return (unsigned char)fn_complete(el, NULL, NULL, | |
579 | break_chars, NULL, NULL, 100, | 575 | break_chars, NULL, NULL, 100, | |
580 | NULL, NULL, NULL, NULL); | 576 | NULL, NULL, NULL, NULL); | |
581 | } | 577 | } |
--- src/lib/libedit/history.c 2011/07/29 15:16:33 1.43
+++ src/lib/libedit/history.c 2011/07/29 20:58:07 1.44
@@ -1,1053 +1,1049 @@ | @@ -1,1053 +1,1049 @@ | |||
1 | /* $NetBSD: history.c,v 1.43 2011/07/29 15:16:33 christos Exp $ */ | 1 | /* $NetBSD: history.c,v 1.44 2011/07/29 20:58:07 christos Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1992, 1993 | 4 | * Copyright (c) 1992, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Christos Zoulas of Cornell University. | 8 | * Christos Zoulas of Cornell University. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | #include "config.h" | 35 | #include "config.h" | |
36 | #if !defined(lint) && !defined(SCCSID) | 36 | #if !defined(lint) && !defined(SCCSID) | |
37 | #if 0 | 37 | #if 0 | |
38 | static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; | 38 | static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; | |
39 | #else | 39 | #else | |
40 | __RCSID("$NetBSD: history.c,v 1.43 2011/07/29 15:16:33 christos Exp $"); | 40 | __RCSID("$NetBSD: history.c,v 1.44 2011/07/29 20:58:07 christos Exp $"); | |
41 | #endif | 41 | #endif | |
42 | #endif /* not lint && not SCCSID */ | 42 | #endif /* not lint && not SCCSID */ | |
43 | 43 | |||
44 | /* | 44 | /* | |
45 | * hist.c: TYPE(History) access functions | 45 | * hist.c: TYPE(History) access functions | |
46 | */ | 46 | */ | |
47 | #include <string.h> | 47 | #include <string.h> | |
48 | #include <stdlib.h> | 48 | #include <stdlib.h> | |
49 | #include <stdarg.h> | 49 | #include <stdarg.h> | |
50 | #ifdef HAVE_VIS_H | |||
51 | #include <vis.h> | 50 | #include <vis.h> | |
52 | #else | |||
53 | #include "vis.h" | |||
54 | #endif | |||
55 | #include <sys/stat.h> | 51 | #include <sys/stat.h> | |
56 | 52 | |||
57 | static const char hist_cookie[] = "_HiStOrY_V2_\n"; | 53 | static const char hist_cookie[] = "_HiStOrY_V2_\n"; | |
58 | 54 | |||
59 | #include "histedit.h" | 55 | #include "histedit.h" | |
60 | #include "chartype.h" | 56 | #include "chartype.h" | |
61 | 57 | |||
62 | typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *); | 58 | typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *); | |
63 | typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *); | 59 | typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *); | |
64 | typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *); | 60 | typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *); | |
65 | typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int); | 61 | typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int); | |
66 | 62 | |||
67 | struct TYPE(history) { | 63 | struct TYPE(history) { | |
68 | void *h_ref; /* Argument for history fcns */ | 64 | void *h_ref; /* Argument for history fcns */ | |
69 | int h_ent; /* Last entry point for history */ | 65 | int h_ent; /* Last entry point for history */ | |
70 | history_gfun_t h_first; /* Get the first element */ | 66 | history_gfun_t h_first; /* Get the first element */ | |
71 | history_gfun_t h_next; /* Get the next element */ | 67 | history_gfun_t h_next; /* Get the next element */ | |
72 | history_gfun_t h_last; /* Get the last element */ | 68 | history_gfun_t h_last; /* Get the last element */ | |
73 | history_gfun_t h_prev; /* Get the previous element */ | 69 | history_gfun_t h_prev; /* Get the previous element */ | |
74 | history_gfun_t h_curr; /* Get the current element */ | 70 | history_gfun_t h_curr; /* Get the current element */ | |
75 | history_sfun_t h_set; /* Set the current element */ | 71 | history_sfun_t h_set; /* Set the current element */ | |
76 | history_sfun_t h_del; /* Set the given element */ | 72 | history_sfun_t h_del; /* Set the given element */ | |
77 | history_vfun_t h_clear; /* Clear the history list */ | 73 | history_vfun_t h_clear; /* Clear the history list */ | |
78 | history_efun_t h_enter; /* Add an element */ | 74 | history_efun_t h_enter; /* Add an element */ | |
79 | history_efun_t h_add; /* Append to an element */ | 75 | history_efun_t h_add; /* Append to an element */ | |
80 | }; | 76 | }; | |
81 | 77 | |||
82 | #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev) | 78 | #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev) | |
83 | #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev) | 79 | #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev) | |
84 | #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev) | 80 | #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev) | |
85 | #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev) | 81 | #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev) | |
86 | #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev) | 82 | #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev) | |
87 | #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n) | 83 | #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n) | |
88 | #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev) | 84 | #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev) | |
89 | #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) | 85 | #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) | |
90 | #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) | 86 | #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) | |
91 | #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n) | 87 | #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n) | |
92 | 88 | |||
93 | #define h_strdup(a) Strdup(a) | 89 | #define h_strdup(a) Strdup(a) | |
94 | #define h_malloc(a) malloc(a) | 90 | #define h_malloc(a) malloc(a) | |
95 | #define h_realloc(a, b) realloc((a), (b)) | 91 | #define h_realloc(a, b) realloc((a), (b)) | |
96 | #define h_free(a) free(a) | 92 | #define h_free(a) free(a) | |
97 | 93 | |||
98 | typedef struct { | 94 | typedef struct { | |
99 | int num; | 95 | int num; | |
100 | Char *str; | 96 | Char *str; | |
101 | } HistEventPrivate; | 97 | } HistEventPrivate; | |
102 | 98 | |||
103 | 99 | |||
104 | 100 | |||
105 | private int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int); | 101 | private int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int); | |
106 | private int history_getsize(TYPE(History) *, TYPE(HistEvent) *); | 102 | private int history_getsize(TYPE(History) *, TYPE(HistEvent) *); | |
107 | private int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int); | 103 | private int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int); | |
108 | private int history_getunique(TYPE(History) *, TYPE(HistEvent) *); | 104 | private int history_getunique(TYPE(History) *, TYPE(HistEvent) *); | |
109 | private int history_set_fun(TYPE(History) *, TYPE(History) *); | 105 | private int history_set_fun(TYPE(History) *, TYPE(History) *); | |
110 | private int history_load(TYPE(History) *, const char *); | 106 | private int history_load(TYPE(History) *, const char *); | |
111 | private int history_save(TYPE(History) *, const char *); | 107 | private int history_save(TYPE(History) *, const char *); | |
112 | private int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int); | 108 | private int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int); | |
113 | private int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int); | 109 | private int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int); | |
114 | private int history_next_string(TYPE(History) *, TYPE(HistEvent) *, const Char *); | 110 | private int history_next_string(TYPE(History) *, TYPE(HistEvent) *, const Char *); | |
115 | private int history_prev_string(TYPE(History) *, TYPE(HistEvent) *, const Char *); | 111 | private int history_prev_string(TYPE(History) *, TYPE(HistEvent) *, const Char *); | |
116 | 112 | |||
117 | 113 | |||
118 | /***********************************************************************/ | 114 | /***********************************************************************/ | |
119 | 115 | |||
120 | /* | 116 | /* | |
121 | * Builtin- history implementation | 117 | * Builtin- history implementation | |
122 | */ | 118 | */ | |
123 | typedef struct hentry_t { | 119 | typedef struct hentry_t { | |
124 | TYPE(HistEvent) ev; /* What we return */ | 120 | TYPE(HistEvent) ev; /* What we return */ | |
125 | void *data; /* data */ | 121 | void *data; /* data */ | |
126 | struct hentry_t *next; /* Next entry */ | 122 | struct hentry_t *next; /* Next entry */ | |
127 | struct hentry_t *prev; /* Previous entry */ | 123 | struct hentry_t *prev; /* Previous entry */ | |
128 | } hentry_t; | 124 | } hentry_t; | |
129 | 125 | |||
130 | typedef struct history_t { | 126 | typedef struct history_t { | |
131 | hentry_t list; /* Fake list header element */ | 127 | hentry_t list; /* Fake list header element */ | |
132 | hentry_t *cursor; /* Current element in the list */ | 128 | hentry_t *cursor; /* Current element in the list */ | |
133 | int max; /* Maximum number of events */ | 129 | int max; /* Maximum number of events */ | |
134 | int cur; /* Current number of events */ | 130 | int cur; /* Current number of events */ | |
135 | int eventid; /* For generation of unique event id */ | 131 | int eventid; /* For generation of unique event id */ | |
136 | int flags; /* TYPE(History) flags */ | 132 | int flags; /* TYPE(History) flags */ | |
137 | #define H_UNIQUE 1 /* Store only unique elements */ | 133 | #define H_UNIQUE 1 /* Store only unique elements */ | |
138 | } history_t; | 134 | } history_t; | |
139 | 135 | |||
140 | private int history_def_next(void *, TYPE(HistEvent) *); | 136 | private int history_def_next(void *, TYPE(HistEvent) *); | |
141 | private int history_def_first(void *, TYPE(HistEvent) *); | 137 | private int history_def_first(void *, TYPE(HistEvent) *); | |
142 | private int history_def_prev(void *, TYPE(HistEvent) *); | 138 | private int history_def_prev(void *, TYPE(HistEvent) *); | |
143 | private int history_def_last(void *, TYPE(HistEvent) *); | 139 | private int history_def_last(void *, TYPE(HistEvent) *); | |
144 | private int history_def_curr(void *, TYPE(HistEvent) *); | 140 | private int history_def_curr(void *, TYPE(HistEvent) *); | |
145 | private int history_def_set(void *, TYPE(HistEvent) *, const int); | 141 | private int history_def_set(void *, TYPE(HistEvent) *, const int); | |
146 | private void history_def_clear(void *, TYPE(HistEvent) *); | 142 | private void history_def_clear(void *, TYPE(HistEvent) *); | |
147 | private int history_def_enter(void *, TYPE(HistEvent) *, const Char *); | 143 | private int history_def_enter(void *, TYPE(HistEvent) *, const Char *); | |
148 | private int history_def_add(void *, TYPE(HistEvent) *, const Char *); | 144 | private int history_def_add(void *, TYPE(HistEvent) *, const Char *); | |
149 | private int history_def_del(void *, TYPE(HistEvent) *, const int); | 145 | private int history_def_del(void *, TYPE(HistEvent) *, const int); | |
150 | 146 | |||
151 | private int history_def_init(void **, TYPE(HistEvent) *, int); | 147 | private int history_def_init(void **, TYPE(HistEvent) *, int); | |
152 | private int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *); | 148 | private int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *); | |
153 | private void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *); | 149 | private void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *); | |
154 | 150 | |||
155 | private int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **); | 151 | private int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **); | |
156 | private int history_set_nth(void *, TYPE(HistEvent) *, int); | 152 | private int history_set_nth(void *, TYPE(HistEvent) *, int); | |
157 | 153 | |||
158 | #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num)) | 154 | #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num)) | |
159 | #define history_def_getsize(p) (((history_t *)p)->cur) | 155 | #define history_def_getsize(p) (((history_t *)p)->cur) | |
160 | #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0) | 156 | #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0) | |
161 | #define history_def_setunique(p, uni) \ | 157 | #define history_def_setunique(p, uni) \ | |
162 | if (uni) \ | 158 | if (uni) \ | |
163 | (((history_t *)p)->flags) |= H_UNIQUE; \ | 159 | (((history_t *)p)->flags) |= H_UNIQUE; \ | |
164 | else \ | 160 | else \ | |
165 | (((history_t *)p)->flags) &= ~H_UNIQUE | 161 | (((history_t *)p)->flags) &= ~H_UNIQUE | |
166 | 162 | |||
167 | #define he_strerror(code) he_errlist[code] | 163 | #define he_strerror(code) he_errlist[code] | |
168 | #define he_seterrev(evp, code) {\ | 164 | #define he_seterrev(evp, code) {\ | |
169 | evp->num = code;\ | 165 | evp->num = code;\ | |
170 | evp->str = he_strerror(code);\ | 166 | evp->str = he_strerror(code);\ | |
171 | } | 167 | } | |
172 | 168 | |||
173 | /* error messages */ | 169 | /* error messages */ | |
174 | static const Char *const he_errlist[] = { | 170 | static const Char *const he_errlist[] = { | |
175 | STR("OK"), | 171 | STR("OK"), | |
176 | STR("unknown error"), | 172 | STR("unknown error"), | |
177 | STR("malloc() failed"), | 173 | STR("malloc() failed"), | |
178 | STR("first event not found"), | 174 | STR("first event not found"), | |
179 | STR("last event not found"), | 175 | STR("last event not found"), | |
180 | STR("empty list"), | 176 | STR("empty list"), | |
181 | STR("no next event"), | 177 | STR("no next event"), | |
182 | STR("no previous event"), | 178 | STR("no previous event"), | |
183 | STR("current event is invalid"), | 179 | STR("current event is invalid"), | |
184 | STR("event not found"), | 180 | STR("event not found"), | |
185 | STR("can't read history from file"), | 181 | STR("can't read history from file"), | |
186 | STR("can't write history"), | 182 | STR("can't write history"), | |
187 | STR("required parameter(s) not supplied"), | 183 | STR("required parameter(s) not supplied"), | |
188 | STR("history size negative"), | 184 | STR("history size negative"), | |
189 | STR("function not allowed with other history-functions-set the default"), | 185 | STR("function not allowed with other history-functions-set the default"), | |
190 | STR("bad parameters") | 186 | STR("bad parameters") | |
191 | }; | 187 | }; | |
192 | /* error codes */ | 188 | /* error codes */ | |
193 | #define _HE_OK 0 | 189 | #define _HE_OK 0 | |
194 | #define _HE_UNKNOWN 1 | 190 | #define _HE_UNKNOWN 1 | |
195 | #define _HE_MALLOC_FAILED 2 | 191 | #define _HE_MALLOC_FAILED 2 | |
196 | #define _HE_FIRST_NOTFOUND 3 | 192 | #define _HE_FIRST_NOTFOUND 3 | |
197 | #define _HE_LAST_NOTFOUND 4 | 193 | #define _HE_LAST_NOTFOUND 4 | |
198 | #define _HE_EMPTY_LIST 5 | 194 | #define _HE_EMPTY_LIST 5 | |
199 | #define _HE_END_REACHED 6 | 195 | #define _HE_END_REACHED 6 | |
200 | #define _HE_START_REACHED 7 | 196 | #define _HE_START_REACHED 7 | |
201 | #define _HE_CURR_INVALID 8 | 197 | #define _HE_CURR_INVALID 8 | |
202 | #define _HE_NOT_FOUND 9 | 198 | #define _HE_NOT_FOUND 9 | |
203 | #define _HE_HIST_READ 10 | 199 | #define _HE_HIST_READ 10 | |
204 | #define _HE_HIST_WRITE 11 | 200 | #define _HE_HIST_WRITE 11 | |
205 | #define _HE_PARAM_MISSING 12 | 201 | #define _HE_PARAM_MISSING 12 | |
206 | #define _HE_SIZE_NEGATIVE 13 | 202 | #define _HE_SIZE_NEGATIVE 13 | |
207 | #define _HE_NOT_ALLOWED 14 | 203 | #define _HE_NOT_ALLOWED 14 | |
208 | #define _HE_BAD_PARAM 15 | 204 | #define _HE_BAD_PARAM 15 | |
209 | 205 | |||
210 | /* history_def_first(): | 206 | /* history_def_first(): | |
211 | * Default function to return the first event in the history. | 207 | * Default function to return the first event in the history. | |
212 | */ | 208 | */ | |
213 | private int | 209 | private int | |
214 | history_def_first(void *p, TYPE(HistEvent) *ev) | 210 | history_def_first(void *p, TYPE(HistEvent) *ev) | |
215 | { | 211 | { | |
216 | history_t *h = (history_t *) p; | 212 | history_t *h = (history_t *) p; | |
217 | 213 | |||
218 | h->cursor = h->list.next; | 214 | h->cursor = h->list.next; | |
219 | if (h->cursor != &h->list) | 215 | if (h->cursor != &h->list) | |
220 | *ev = h->cursor->ev; | 216 | *ev = h->cursor->ev; | |
221 | else { | 217 | else { | |
222 | he_seterrev(ev, _HE_FIRST_NOTFOUND); | 218 | he_seterrev(ev, _HE_FIRST_NOTFOUND); | |
223 | return -1; | 219 | return -1; | |
224 | } | 220 | } | |
225 | 221 | |||
226 | return 0; | 222 | return 0; | |
227 | } | 223 | } | |
228 | 224 | |||
229 | 225 | |||
230 | /* history_def_last(): | 226 | /* history_def_last(): | |
231 | * Default function to return the last event in the history. | 227 | * Default function to return the last event in the history. | |
232 | */ | 228 | */ | |
233 | private int | 229 | private int | |
234 | history_def_last(void *p, TYPE(HistEvent) *ev) | 230 | history_def_last(void *p, TYPE(HistEvent) *ev) | |
235 | { | 231 | { | |
236 | history_t *h = (history_t *) p; | 232 | history_t *h = (history_t *) p; | |
237 | 233 | |||
238 | h->cursor = h->list.prev; | 234 | h->cursor = h->list.prev; | |
239 | if (h->cursor != &h->list) | 235 | if (h->cursor != &h->list) | |
240 | *ev = h->cursor->ev; | 236 | *ev = h->cursor->ev; | |
241 | else { | 237 | else { | |
242 | he_seterrev(ev, _HE_LAST_NOTFOUND); | 238 | he_seterrev(ev, _HE_LAST_NOTFOUND); | |
243 | return -1; | 239 | return -1; | |
244 | } | 240 | } | |
245 | 241 | |||
246 | return 0; | 242 | return 0; | |
247 | } | 243 | } | |
248 | 244 | |||
249 | 245 | |||
250 | /* history_def_next(): | 246 | /* history_def_next(): | |
251 | * Default function to return the next event in the history. | 247 | * Default function to return the next event in the history. | |
252 | */ | 248 | */ | |
253 | private int | 249 | private int | |
254 | history_def_next(void *p, TYPE(HistEvent) *ev) | 250 | history_def_next(void *p, TYPE(HistEvent) *ev) | |
255 | { | 251 | { | |
256 | history_t *h = (history_t *) p; | 252 | history_t *h = (history_t *) p; | |
257 | 253 | |||
258 | if (h->cursor == &h->list) { | 254 | if (h->cursor == &h->list) { | |
259 | he_seterrev(ev, _HE_EMPTY_LIST); | 255 | he_seterrev(ev, _HE_EMPTY_LIST); | |
260 | return -1; | 256 | return -1; | |
261 | } | 257 | } | |
262 | 258 | |||
263 | if (h->cursor->next == &h->list) { | 259 | if (h->cursor->next == &h->list) { | |
264 | he_seterrev(ev, _HE_END_REACHED); | 260 | he_seterrev(ev, _HE_END_REACHED); | |
265 | return -1; | 261 | return -1; | |
266 | } | 262 | } | |
267 | 263 | |||
268 | h->cursor = h->cursor->next; | 264 | h->cursor = h->cursor->next; | |
269 | *ev = h->cursor->ev; | 265 | *ev = h->cursor->ev; | |
270 | 266 | |||
271 | return 0; | 267 | return 0; | |
272 | } | 268 | } | |
273 | 269 | |||
274 | 270 | |||
275 | /* history_def_prev(): | 271 | /* history_def_prev(): | |
276 | * Default function to return the previous event in the history. | 272 | * Default function to return the previous event in the history. | |
277 | */ | 273 | */ | |
278 | private int | 274 | private int | |
279 | history_def_prev(void *p, TYPE(HistEvent) *ev) | 275 | history_def_prev(void *p, TYPE(HistEvent) *ev) | |
280 | { | 276 | { | |
281 | history_t *h = (history_t *) p; | 277 | history_t *h = (history_t *) p; | |
282 | 278 | |||
283 | if (h->cursor == &h->list) { | 279 | if (h->cursor == &h->list) { | |
284 | he_seterrev(ev, | 280 | he_seterrev(ev, | |
285 | (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); | 281 | (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); | |
286 | return -1; | 282 | return -1; | |
287 | } | 283 | } | |
288 | 284 | |||
289 | if (h->cursor->prev == &h->list) { | 285 | if (h->cursor->prev == &h->list) { | |
290 | he_seterrev(ev, _HE_START_REACHED); | 286 | he_seterrev(ev, _HE_START_REACHED); | |
291 | return -1; | 287 | return -1; | |
292 | } | 288 | } | |
293 | 289 | |||
294 | h->cursor = h->cursor->prev; | 290 | h->cursor = h->cursor->prev; | |
295 | *ev = h->cursor->ev; | 291 | *ev = h->cursor->ev; | |
296 | 292 | |||
297 | return 0; | 293 | return 0; | |
298 | } | 294 | } | |
299 | 295 | |||
300 | 296 | |||
301 | /* history_def_curr(): | 297 | /* history_def_curr(): | |
302 | * Default function to return the current event in the history. | 298 | * Default function to return the current event in the history. | |
303 | */ | 299 | */ | |
304 | private int | 300 | private int | |
305 | history_def_curr(void *p, TYPE(HistEvent) *ev) | 301 | history_def_curr(void *p, TYPE(HistEvent) *ev) | |
306 | { | 302 | { | |
307 | history_t *h = (history_t *) p; | 303 | history_t *h = (history_t *) p; | |
308 | 304 | |||
309 | if (h->cursor != &h->list) | 305 | if (h->cursor != &h->list) | |
310 | *ev = h->cursor->ev; | 306 | *ev = h->cursor->ev; | |
311 | else { | 307 | else { | |
312 | he_seterrev(ev, | 308 | he_seterrev(ev, | |
313 | (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST); | 309 | (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST); | |
314 | return -1; | 310 | return -1; | |
315 | } | 311 | } | |
316 | 312 | |||
317 | return 0; | 313 | return 0; | |
318 | } | 314 | } | |
319 | 315 | |||
320 | 316 | |||
321 | /* history_def_set(): | 317 | /* history_def_set(): | |
322 | * Default function to set the current event in the history to the | 318 | * Default function to set the current event in the history to the | |
323 | * given one. | 319 | * given one. | |
324 | */ | 320 | */ | |
325 | private int | 321 | private int | |
326 | history_def_set(void *p, TYPE(HistEvent) *ev, const int n) | 322 | history_def_set(void *p, TYPE(HistEvent) *ev, const int n) | |
327 | { | 323 | { | |
328 | history_t *h = (history_t *) p; | 324 | history_t *h = (history_t *) p; | |
329 | 325 | |||
330 | if (h->cur == 0) { | 326 | if (h->cur == 0) { | |
331 | he_seterrev(ev, _HE_EMPTY_LIST); | 327 | he_seterrev(ev, _HE_EMPTY_LIST); | |
332 | return -1; | 328 | return -1; | |
333 | } | 329 | } | |
334 | if (h->cursor == &h->list || h->cursor->ev.num != n) { | 330 | if (h->cursor == &h->list || h->cursor->ev.num != n) { | |
335 | for (h->cursor = h->list.next; h->cursor != &h->list; | 331 | for (h->cursor = h->list.next; h->cursor != &h->list; | |
336 | h->cursor = h->cursor->next) | 332 | h->cursor = h->cursor->next) | |
337 | if (h->cursor->ev.num == n) | 333 | if (h->cursor->ev.num == n) | |
338 | break; | 334 | break; | |
339 | } | 335 | } | |
340 | if (h->cursor == &h->list) { | 336 | if (h->cursor == &h->list) { | |
341 | he_seterrev(ev, _HE_NOT_FOUND); | 337 | he_seterrev(ev, _HE_NOT_FOUND); | |
342 | return -1; | 338 | return -1; | |
343 | } | 339 | } | |
344 | return 0; | 340 | return 0; | |
345 | } | 341 | } | |
346 | 342 | |||
347 | 343 | |||
348 | /* history_set_nth(): | 344 | /* history_set_nth(): | |
349 | * Default function to set the current event in the history to the | 345 | * Default function to set the current event in the history to the | |
350 | * n-th one. | 346 | * n-th one. | |
351 | */ | 347 | */ | |
352 | private int | 348 | private int | |
353 | history_set_nth(void *p, TYPE(HistEvent) *ev, int n) | 349 | history_set_nth(void *p, TYPE(HistEvent) *ev, int n) | |
354 | { | 350 | { | |
355 | history_t *h = (history_t *) p; | 351 | history_t *h = (history_t *) p; | |
356 | 352 | |||
357 | if (h->cur == 0) { | 353 | if (h->cur == 0) { | |
358 | he_seterrev(ev, _HE_EMPTY_LIST); | 354 | he_seterrev(ev, _HE_EMPTY_LIST); | |
359 | return -1; | 355 | return -1; | |
360 | } | 356 | } | |
361 | for (h->cursor = h->list.prev; h->cursor != &h->list; | 357 | for (h->cursor = h->list.prev; h->cursor != &h->list; | |
362 | h->cursor = h->cursor->prev) | 358 | h->cursor = h->cursor->prev) | |
363 | if (n-- <= 0) | 359 | if (n-- <= 0) | |
364 | break; | 360 | break; | |
365 | if (h->cursor == &h->list) { | 361 | if (h->cursor == &h->list) { | |
366 | he_seterrev(ev, _HE_NOT_FOUND); | 362 | he_seterrev(ev, _HE_NOT_FOUND); | |
367 | return -1; | 363 | return -1; | |
368 | } | 364 | } | |
369 | return 0; | 365 | return 0; | |
370 | } | 366 | } | |
371 | 367 | |||
372 | 368 | |||
373 | /* history_def_add(): | 369 | /* history_def_add(): | |
374 | * Append string to element | 370 | * Append string to element | |
375 | */ | 371 | */ | |
376 | private int | 372 | private int | |
377 | history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str) | 373 | history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str) | |
378 | { | 374 | { | |
379 | history_t *h = (history_t *) p; | 375 | history_t *h = (history_t *) p; | |
380 | size_t len; | 376 | size_t len; | |
381 | Char *s; | 377 | Char *s; | |
382 | HistEventPrivate *evp = (void *)&h->cursor->ev; | 378 | HistEventPrivate *evp = (void *)&h->cursor->ev; | |
383 | 379 | |||
384 | if (h->cursor == &h->list) | 380 | if (h->cursor == &h->list) | |
385 | return history_def_enter(p, ev, str); | 381 | return history_def_enter(p, ev, str); | |
386 | len = Strlen(evp->str) + Strlen(str) + 1; | 382 | len = Strlen(evp->str) + Strlen(str) + 1; | |
387 | s = h_malloc(len * sizeof(*s)); | 383 | s = h_malloc(len * sizeof(*s)); | |
388 | if (s == NULL) { | 384 | if (s == NULL) { | |
389 | he_seterrev(ev, _HE_MALLOC_FAILED); | 385 | he_seterrev(ev, _HE_MALLOC_FAILED); | |
390 | return -1; | 386 | return -1; | |
391 | } | 387 | } | |
392 | (void) Strncpy(s, h->cursor->ev.str, len); | 388 | (void) Strncpy(s, h->cursor->ev.str, len); | |
393 | s[len - 1] = '\0'; | 389 | s[len - 1] = '\0'; | |
394 | (void) Strncat(s, str, len - Strlen(s) - 1); | 390 | (void) Strncat(s, str, len - Strlen(s) - 1); | |
395 | h_free(evp->str); | 391 | h_free(evp->str); | |
396 | evp->str = s; | 392 | evp->str = s; | |
397 | *ev = h->cursor->ev; | 393 | *ev = h->cursor->ev; | |
398 | return 0; | 394 | return 0; | |
399 | } | 395 | } | |
400 | 396 | |||
401 | 397 | |||
402 | private int | 398 | private int | |
403 | history_deldata_nth(history_t *h, TYPE(HistEvent) *ev, | 399 | history_deldata_nth(history_t *h, TYPE(HistEvent) *ev, | |
404 | int num, void **data) | 400 | int num, void **data) | |
405 | { | 401 | { | |
406 | if (history_set_nth(h, ev, num) != 0) | 402 | if (history_set_nth(h, ev, num) != 0) | |
407 | return -1; | 403 | return -1; | |
408 | /* magic value to skip delete (just set to n-th history) */ | 404 | /* magic value to skip delete (just set to n-th history) */ | |
409 | if (data == (void **)-1) | 405 | if (data == (void **)-1) | |
410 | return 0; | 406 | return 0; | |
411 | ev->str = Strdup(h->cursor->ev.str); | 407 | ev->str = Strdup(h->cursor->ev.str); | |
412 | ev->num = h->cursor->ev.num; | 408 | ev->num = h->cursor->ev.num; | |
413 | if (data) | 409 | if (data) | |
414 | *data = h->cursor->data; | 410 | *data = h->cursor->data; | |
415 | history_def_delete(h, ev, h->cursor); | 411 | history_def_delete(h, ev, h->cursor); | |
416 | return 0; | 412 | return 0; | |
417 | } | 413 | } | |
418 | 414 | |||
419 | 415 | |||
420 | /* history_def_del(): | 416 | /* history_def_del(): | |
421 | * Delete element hp of the h list | 417 | * Delete element hp of the h list | |
422 | */ | 418 | */ | |
423 | /* ARGSUSED */ | 419 | /* ARGSUSED */ | |
424 | private int | 420 | private int | |
425 | history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)), | 421 | history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)), | |
426 | const int num) | 422 | const int num) | |
427 | { | 423 | { | |
428 | history_t *h = (history_t *) p; | 424 | history_t *h = (history_t *) p; | |
429 | if (history_def_set(h, ev, num) != 0) | 425 | if (history_def_set(h, ev, num) != 0) | |
430 | return -1; | 426 | return -1; | |
431 | ev->str = Strdup(h->cursor->ev.str); | 427 | ev->str = Strdup(h->cursor->ev.str); | |
432 | ev->num = h->cursor->ev.num; | 428 | ev->num = h->cursor->ev.num; | |
433 | history_def_delete(h, ev, h->cursor); | 429 | history_def_delete(h, ev, h->cursor); | |
434 | return 0; | 430 | return 0; | |
435 | } | 431 | } | |
436 | 432 | |||
437 | 433 | |||
438 | /* history_def_delete(): | 434 | /* history_def_delete(): | |
439 | * Delete element hp of the h list | 435 | * Delete element hp of the h list | |
440 | */ | 436 | */ | |
441 | /* ARGSUSED */ | 437 | /* ARGSUSED */ | |
442 | private void | 438 | private void | |
443 | history_def_delete(history_t *h, | 439 | history_def_delete(history_t *h, | |
444 | TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp) | 440 | TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp) | |
445 | { | 441 | { | |
446 | HistEventPrivate *evp = (void *)&hp->ev; | 442 | HistEventPrivate *evp = (void *)&hp->ev; | |
447 | if (hp == &h->list) | 443 | if (hp == &h->list) | |
448 | abort(); | 444 | abort(); | |
449 | if (h->cursor == hp) { | 445 | if (h->cursor == hp) { | |
450 | h->cursor = hp->prev; | 446 | h->cursor = hp->prev; | |
451 | if (h->cursor == &h->list) | 447 | if (h->cursor == &h->list) | |
452 | h->cursor = hp->next; | 448 | h->cursor = hp->next; | |
453 | } | 449 | } | |
454 | hp->prev->next = hp->next; | 450 | hp->prev->next = hp->next; | |
455 | hp->next->prev = hp->prev; | 451 | hp->next->prev = hp->prev; | |
456 | h_free(evp->str); | 452 | h_free(evp->str); | |
457 | h_free(hp); | 453 | h_free(hp); | |
458 | h->cur--; | 454 | h->cur--; | |
459 | } | 455 | } | |
460 | 456 | |||
461 | 457 | |||
462 | /* history_def_insert(): | 458 | /* history_def_insert(): | |
463 | * Insert element with string str in the h list | 459 | * Insert element with string str in the h list | |
464 | */ | 460 | */ | |
465 | private int | 461 | private int | |
466 | history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str) | 462 | history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str) | |
467 | { | 463 | { | |
468 | hentry_t *c; | 464 | hentry_t *c; | |
469 | 465 | |||
470 | c = h_malloc(sizeof(*c)); | 466 | c = h_malloc(sizeof(*c)); | |
471 | if (c == NULL) | 467 | if (c == NULL) | |
472 | goto oomem; | 468 | goto oomem; | |
473 | if ((c->ev.str = h_strdup(str)) == NULL) { | 469 | if ((c->ev.str = h_strdup(str)) == NULL) { | |
474 | h_free(c); | 470 | h_free(c); | |
475 | goto oomem; | 471 | goto oomem; | |
476 | } | 472 | } | |
477 | c->data = NULL; | 473 | c->data = NULL; | |
478 | c->ev.num = ++h->eventid; | 474 | c->ev.num = ++h->eventid; | |
479 | c->next = h->list.next; | 475 | c->next = h->list.next; | |
480 | c->prev = &h->list; | 476 | c->prev = &h->list; | |
481 | h->list.next->prev = c; | 477 | h->list.next->prev = c; | |
482 | h->list.next = c; | 478 | h->list.next = c; | |
483 | h->cur++; | 479 | h->cur++; | |
484 | h->cursor = c; | 480 | h->cursor = c; | |
485 | 481 | |||
486 | *ev = c->ev; | 482 | *ev = c->ev; | |
487 | return 0; | 483 | return 0; | |
488 | oomem: | 484 | oomem: | |
489 | he_seterrev(ev, _HE_MALLOC_FAILED); | 485 | he_seterrev(ev, _HE_MALLOC_FAILED); | |
490 | return -1; | 486 | return -1; | |
491 | } | 487 | } | |
492 | 488 | |||
493 | 489 | |||
494 | /* history_def_enter(): | 490 | /* history_def_enter(): | |
495 | * Default function to enter an item in the history | 491 | * Default function to enter an item in the history | |
496 | */ | 492 | */ | |
497 | private int | 493 | private int | |
498 | history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str) | 494 | history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str) | |
499 | { | 495 | { | |
500 | history_t *h = (history_t *) p; | 496 | history_t *h = (history_t *) p; | |
501 | 497 | |||
502 | if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list && | 498 | if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list && | |
503 | Strcmp(h->list.next->ev.str, str) == 0) | 499 | Strcmp(h->list.next->ev.str, str) == 0) | |
504 | return 0; | 500 | return 0; | |
505 | 501 | |||
506 | if (history_def_insert(h, ev, str) == -1) | 502 | if (history_def_insert(h, ev, str) == -1) | |
507 | return -1; /* error, keep error message */ | 503 | return -1; /* error, keep error message */ | |
508 | 504 | |||
509 | /* | 505 | /* | |
510 | * Always keep at least one entry. | 506 | * Always keep at least one entry. | |
511 | * This way we don't have to check for the empty list. | 507 | * This way we don't have to check for the empty list. | |
512 | */ | 508 | */ | |
513 | while (h->cur > h->max && h->cur > 0) | 509 | while (h->cur > h->max && h->cur > 0) | |
514 | history_def_delete(h, ev, h->list.prev); | 510 | history_def_delete(h, ev, h->list.prev); | |
515 | 511 | |||
516 | return 1; | 512 | return 1; | |
517 | } | 513 | } | |
518 | 514 | |||
519 | 515 | |||
520 | /* history_def_init(): | 516 | /* history_def_init(): | |
521 | * Default history initialization function | 517 | * Default history initialization function | |
522 | */ | 518 | */ | |
523 | /* ARGSUSED */ | 519 | /* ARGSUSED */ | |
524 | private int | 520 | private int | |
525 | history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n) | 521 | history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n) | |
526 | { | 522 | { | |
527 | history_t *h = (history_t *) h_malloc(sizeof(*h)); | 523 | history_t *h = (history_t *) h_malloc(sizeof(*h)); | |
528 | if (h == NULL) | 524 | if (h == NULL) | |
529 | return -1; | 525 | return -1; | |
530 | 526 | |||
531 | if (n <= 0) | 527 | if (n <= 0) | |
532 | n = 0; | 528 | n = 0; | |
533 | h->eventid = 0; | 529 | h->eventid = 0; | |
534 | h->cur = 0; | 530 | h->cur = 0; | |
535 | h->max = n; | 531 | h->max = n; | |
536 | h->list.next = h->list.prev = &h->list; | 532 | h->list.next = h->list.prev = &h->list; | |
537 | h->list.ev.str = NULL; | 533 | h->list.ev.str = NULL; | |
538 | h->list.ev.num = 0; | 534 | h->list.ev.num = 0; | |
539 | h->cursor = &h->list; | 535 | h->cursor = &h->list; | |
540 | h->flags = 0; | 536 | h->flags = 0; | |
541 | *p = h; | 537 | *p = h; | |
542 | return 0; | 538 | return 0; | |
543 | } | 539 | } | |
544 | 540 | |||
545 | 541 | |||
546 | /* history_def_clear(): | 542 | /* history_def_clear(): | |
547 | * Default history cleanup function | 543 | * Default history cleanup function | |
548 | */ | 544 | */ | |
549 | private void | 545 | private void | |
550 | history_def_clear(void *p, TYPE(HistEvent) *ev) | 546 | history_def_clear(void *p, TYPE(HistEvent) *ev) | |
551 | { | 547 | { | |
552 | history_t *h = (history_t *) p; | 548 | history_t *h = (history_t *) p; | |
553 | 549 | |||
554 | while (h->list.prev != &h->list) | 550 | while (h->list.prev != &h->list) | |
555 | history_def_delete(h, ev, h->list.prev); | 551 | history_def_delete(h, ev, h->list.prev); | |
556 | h->cursor = &h->list; | 552 | h->cursor = &h->list; | |
557 | h->eventid = 0; | 553 | h->eventid = 0; | |
558 | h->cur = 0; | 554 | h->cur = 0; | |
559 | } | 555 | } | |
560 | 556 | |||
561 | 557 | |||
562 | 558 | |||
563 | 559 | |||
564 | /************************************************************************/ | 560 | /************************************************************************/ | |
565 | 561 | |||
566 | /* history_init(): | 562 | /* history_init(): | |
567 | * Initialization function. | 563 | * Initialization function. | |
568 | */ | 564 | */ | |
569 | public TYPE(History) * | 565 | public TYPE(History) * | |
570 | FUN(history,init)(void) | 566 | FUN(history,init)(void) | |
571 | { | 567 | { | |
572 | TYPE(HistEvent) ev; | 568 | TYPE(HistEvent) ev; | |
573 | TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h)); | 569 | TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h)); | |
574 | if (h == NULL) | 570 | if (h == NULL) | |
575 | return NULL; | 571 | return NULL; | |
576 | 572 | |||
577 | if (history_def_init(&h->h_ref, &ev, 0) == -1) { | 573 | if (history_def_init(&h->h_ref, &ev, 0) == -1) { | |
578 | h_free(h); | 574 | h_free(h); | |
579 | return NULL; | 575 | return NULL; | |
580 | } | 576 | } | |
581 | h->h_ent = -1; | 577 | h->h_ent = -1; | |
582 | h->h_next = history_def_next; | 578 | h->h_next = history_def_next; | |
583 | h->h_first = history_def_first; | 579 | h->h_first = history_def_first; | |
584 | h->h_last = history_def_last; | 580 | h->h_last = history_def_last; | |
585 | h->h_prev = history_def_prev; | 581 | h->h_prev = history_def_prev; | |
586 | h->h_curr = history_def_curr; | 582 | h->h_curr = history_def_curr; | |
587 | h->h_set = history_def_set; | 583 | h->h_set = history_def_set; | |
588 | h->h_clear = history_def_clear; | 584 | h->h_clear = history_def_clear; | |
589 | h->h_enter = history_def_enter; | 585 | h->h_enter = history_def_enter; | |
590 | h->h_add = history_def_add; | 586 | h->h_add = history_def_add; | |
591 | h->h_del = history_def_del; | 587 | h->h_del = history_def_del; | |
592 | 588 | |||
593 | return h; | 589 | return h; | |
594 | } | 590 | } | |
595 | 591 | |||
596 | 592 | |||
597 | /* history_end(): | 593 | /* history_end(): | |
598 | * clean up history; | 594 | * clean up history; | |
599 | */ | 595 | */ | |
600 | public void | 596 | public void | |
601 | FUN(history,end)(TYPE(History) *h) | 597 | FUN(history,end)(TYPE(History) *h) | |
602 | { | 598 | { | |
603 | TYPE(HistEvent) ev; | 599 | TYPE(HistEvent) ev; | |
604 | 600 | |||
605 | if (h->h_next == history_def_next) | 601 | if (h->h_next == history_def_next) | |
606 | history_def_clear(h->h_ref, &ev); | 602 | history_def_clear(h->h_ref, &ev); | |
607 | h_free(h->h_ref); | 603 | h_free(h->h_ref); | |
608 | h_free(h); | 604 | h_free(h); | |
609 | } | 605 | } | |
610 | 606 | |||
611 | 607 | |||
612 | 608 | |||
613 | /* history_setsize(): | 609 | /* history_setsize(): | |
614 | * Set history number of events | 610 | * Set history number of events | |
615 | */ | 611 | */ | |
616 | private int | 612 | private int | |
617 | history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num) | 613 | history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num) | |
618 | { | 614 | { | |
619 | 615 | |||
620 | if (h->h_next != history_def_next) { | 616 | if (h->h_next != history_def_next) { | |
621 | he_seterrev(ev, _HE_NOT_ALLOWED); | 617 | he_seterrev(ev, _HE_NOT_ALLOWED); | |
622 | return -1; | 618 | return -1; | |
623 | } | 619 | } | |
624 | if (num < 0) { | 620 | if (num < 0) { | |
625 | he_seterrev(ev, _HE_BAD_PARAM); | 621 | he_seterrev(ev, _HE_BAD_PARAM); | |
626 | return -1; | 622 | return -1; | |
627 | } | 623 | } | |
628 | history_def_setsize(h->h_ref, num); | 624 | history_def_setsize(h->h_ref, num); | |
629 | return 0; | 625 | return 0; | |
630 | } | 626 | } | |
631 | 627 | |||
632 | 628 | |||
633 | /* history_getsize(): | 629 | /* history_getsize(): | |
634 | * Get number of events currently in history | 630 | * Get number of events currently in history | |
635 | */ | 631 | */ | |
636 | private int | 632 | private int | |
637 | history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev) | 633 | history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev) | |
638 | { | 634 | { | |
639 | if (h->h_next != history_def_next) { | 635 | if (h->h_next != history_def_next) { | |
640 | he_seterrev(ev, _HE_NOT_ALLOWED); | 636 | he_seterrev(ev, _HE_NOT_ALLOWED); | |
641 | return -1; | 637 | return -1; | |
642 | } | 638 | } | |
643 | ev->num = history_def_getsize(h->h_ref); | 639 | ev->num = history_def_getsize(h->h_ref); | |
644 | if (ev->num < -1) { | 640 | if (ev->num < -1) { | |
645 | he_seterrev(ev, _HE_SIZE_NEGATIVE); | 641 | he_seterrev(ev, _HE_SIZE_NEGATIVE); | |
646 | return -1; | 642 | return -1; | |
647 | } | 643 | } | |
648 | return 0; | 644 | return 0; | |
649 | } | 645 | } | |
650 | 646 | |||
651 | 647 | |||
652 | /* history_setunique(): | 648 | /* history_setunique(): | |
653 | * Set if adjacent equal events should not be entered in history. | 649 | * Set if adjacent equal events should not be entered in history. | |
654 | */ | 650 | */ | |
655 | private int | 651 | private int | |
656 | history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni) | 652 | history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni) | |
657 | { | 653 | { | |
658 | 654 | |||
659 | if (h->h_next != history_def_next) { | 655 | if (h->h_next != history_def_next) { | |
660 | he_seterrev(ev, _HE_NOT_ALLOWED); | 656 | he_seterrev(ev, _HE_NOT_ALLOWED); | |
661 | return -1; | 657 | return -1; | |
662 | } | 658 | } | |
663 | history_def_setunique(h->h_ref, uni); | 659 | history_def_setunique(h->h_ref, uni); | |
664 | return 0; | 660 | return 0; | |
665 | } | 661 | } | |
666 | 662 | |||
667 | 663 | |||
668 | /* history_getunique(): | 664 | /* history_getunique(): | |
669 | * Get if adjacent equal events should not be entered in history. | 665 | * Get if adjacent equal events should not be entered in history. | |
670 | */ | 666 | */ | |
671 | private int | 667 | private int | |
672 | history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev) | 668 | history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev) | |
673 | { | 669 | { | |
674 | if (h->h_next != history_def_next) { | 670 | if (h->h_next != history_def_next) { | |
675 | he_seterrev(ev, _HE_NOT_ALLOWED); | 671 | he_seterrev(ev, _HE_NOT_ALLOWED); | |
676 | return -1; | 672 | return -1; | |
677 | } | 673 | } | |
678 | ev->num = history_def_getunique(h->h_ref); | 674 | ev->num = history_def_getunique(h->h_ref); | |
679 | return 0; | 675 | return 0; | |
680 | } | 676 | } | |
681 | 677 | |||
682 | 678 | |||
683 | /* history_set_fun(): | 679 | /* history_set_fun(): | |
684 | * Set history functions | 680 | * Set history functions | |
685 | */ | 681 | */ | |
686 | private int | 682 | private int | |
687 | history_set_fun(TYPE(History) *h, TYPE(History) *nh) | 683 | history_set_fun(TYPE(History) *h, TYPE(History) *nh) | |
688 | { | 684 | { | |
689 | TYPE(HistEvent) ev; | 685 | TYPE(HistEvent) ev; | |
690 | 686 | |||
691 | if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || | 687 | if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || | |
692 | nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || | 688 | nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || | |
693 | nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || | 689 | nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || | |
694 | nh->h_del == NULL || nh->h_ref == NULL) { | 690 | nh->h_del == NULL || nh->h_ref == NULL) { | |
695 | if (h->h_next != history_def_next) { | 691 | if (h->h_next != history_def_next) { | |
696 | history_def_init(&h->h_ref, &ev, 0); | 692 | history_def_init(&h->h_ref, &ev, 0); | |
697 | h->h_first = history_def_first; | 693 | h->h_first = history_def_first; | |
698 | h->h_next = history_def_next; | 694 | h->h_next = history_def_next; | |
699 | h->h_last = history_def_last; | 695 | h->h_last = history_def_last; | |
700 | h->h_prev = history_def_prev; | 696 | h->h_prev = history_def_prev; | |
701 | h->h_curr = history_def_curr; | 697 | h->h_curr = history_def_curr; | |
702 | h->h_set = history_def_set; | 698 | h->h_set = history_def_set; | |
703 | h->h_clear = history_def_clear; | 699 | h->h_clear = history_def_clear; | |
704 | h->h_enter = history_def_enter; | 700 | h->h_enter = history_def_enter; | |
705 | h->h_add = history_def_add; | 701 | h->h_add = history_def_add; | |
706 | h->h_del = history_def_del; | 702 | h->h_del = history_def_del; | |
707 | } | 703 | } | |
708 | return -1; | 704 | return -1; | |
709 | } | 705 | } | |
710 | if (h->h_next == history_def_next) | 706 | if (h->h_next == history_def_next) | |
711 | history_def_clear(h->h_ref, &ev); | 707 | history_def_clear(h->h_ref, &ev); | |
712 | 708 | |||
713 | h->h_ent = -1; | 709 | h->h_ent = -1; | |
714 | h->h_first = nh->h_first; | 710 | h->h_first = nh->h_first; | |
715 | h->h_next = nh->h_next; | 711 | h->h_next = nh->h_next; | |
716 | h->h_last = nh->h_last; | 712 | h->h_last = nh->h_last; | |
717 | h->h_prev = nh->h_prev; | 713 | h->h_prev = nh->h_prev; | |
718 | h->h_curr = nh->h_curr; | 714 | h->h_curr = nh->h_curr; | |
719 | h->h_set = nh->h_set; | 715 | h->h_set = nh->h_set; | |
720 | h->h_clear = nh->h_clear; | 716 | h->h_clear = nh->h_clear; | |
721 | h->h_enter = nh->h_enter; | 717 | h->h_enter = nh->h_enter; | |
722 | h->h_add = nh->h_add; | 718 | h->h_add = nh->h_add; | |
723 | h->h_del = nh->h_del; | 719 | h->h_del = nh->h_del; | |
724 | 720 | |||
725 | return 0; | 721 | return 0; | |
726 | } | 722 | } | |
727 | 723 | |||
728 | 724 | |||
729 | /* history_load(): | 725 | /* history_load(): | |
730 | * TYPE(History) load function | 726 | * TYPE(History) load function | |
731 | */ | 727 | */ | |
732 | private int | 728 | private int | |
733 | history_load(TYPE(History) *h, const char *fname) | 729 | history_load(TYPE(History) *h, const char *fname) | |
734 | { | 730 | { | |
735 | FILE *fp; | 731 | FILE *fp; | |
736 | char *line; | 732 | char *line; | |
737 | size_t sz, max_size; | 733 | size_t sz, max_size; | |
738 | char *ptr; | 734 | char *ptr; | |
739 | int i = -1; | 735 | int i = -1; | |
740 | TYPE(HistEvent) ev; | 736 | TYPE(HistEvent) ev; | |
741 | #ifdef WIDECHAR | 737 | #ifdef WIDECHAR | |
742 | static ct_buffer_t conv; | 738 | static ct_buffer_t conv; | |
743 | #endif | 739 | #endif | |
744 | 740 | |||
745 | if ((fp = fopen(fname, "r")) == NULL) | 741 | if ((fp = fopen(fname, "r")) == NULL) | |
746 | return i; | 742 | return i; | |
747 | 743 | |||
748 | if ((line = fgetln(fp, &sz)) == NULL) | 744 | if ((line = fgetln(fp, &sz)) == NULL) | |
749 | goto done; | 745 | goto done; | |
750 | 746 | |||
751 | if (strncmp(line, hist_cookie, sz) != 0) | 747 | if (strncmp(line, hist_cookie, sz) != 0) | |
752 | goto done; | 748 | goto done; | |
753 | 749 | |||
754 | ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); | 750 | ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); | |
755 | if (ptr == NULL) | 751 | if (ptr == NULL) | |
756 | goto done; | 752 | goto done; | |
757 | for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) { | 753 | for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) { | |
758 | char c = line[sz]; | 754 | char c = line[sz]; | |
759 | 755 | |||
760 | if (sz != 0 && line[sz - 1] == '\n') | 756 | if (sz != 0 && line[sz - 1] == '\n') | |
761 | line[--sz] = '\0'; | 757 | line[--sz] = '\0'; | |
762 | else | 758 | else | |
763 | line[sz] = '\0'; | 759 | line[sz] = '\0'; | |
764 | 760 | |||
765 | if (max_size < sz) { | 761 | if (max_size < sz) { | |
766 | char *nptr; | 762 | char *nptr; | |
767 | max_size = (sz + 1024) & ~1023; | 763 | max_size = (sz + 1024) & ~1023; | |
768 | nptr = h_realloc(ptr, max_size * sizeof(*ptr)); | 764 | nptr = h_realloc(ptr, max_size * sizeof(*ptr)); | |
769 | if (nptr == NULL) { | 765 | if (nptr == NULL) { | |
770 | i = -1; | 766 | i = -1; | |
771 | goto oomem; | 767 | goto oomem; | |
772 | } | 768 | } | |
773 | ptr = nptr; | 769 | ptr = nptr; | |
774 | } | 770 | } | |
775 | (void) strunvis(ptr, line); | 771 | (void) strunvis(ptr, line); | |
776 | line[sz] = c; | 772 | line[sz] = c; | |
777 | if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) { | 773 | if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) { | |
778 | i = -1; | 774 | i = -1; | |
779 | goto oomem; | 775 | goto oomem; | |
780 | } | 776 | } | |
781 | } | 777 | } | |
782 | oomem: | 778 | oomem: | |
783 | h_free(ptr); | 779 | h_free(ptr); | |
784 | done: | 780 | done: | |
785 | (void) fclose(fp); | 781 | (void) fclose(fp); | |
786 | return i; | 782 | return i; | |
787 | } | 783 | } | |
788 | 784 | |||
789 | 785 | |||
790 | /* history_save(): | 786 | /* history_save(): | |
791 | * TYPE(History) save function | 787 | * TYPE(History) save function | |
792 | */ | 788 | */ | |
793 | private int | 789 | private int | |
794 | history_save(TYPE(History) *h, const char *fname) | 790 | history_save(TYPE(History) *h, const char *fname) | |
795 | { | 791 | { | |
796 | FILE *fp; | 792 | FILE *fp; | |
797 | TYPE(HistEvent) ev; | 793 | TYPE(HistEvent) ev; | |
798 | int i = -1, retval; | 794 | int i = -1, retval; | |
799 | size_t len, max_size; | 795 | size_t len, max_size; | |
800 | char *ptr; | 796 | char *ptr; | |
801 | const char *str; | 797 | const char *str; | |
802 | #ifdef WIDECHAR | 798 | #ifdef WIDECHAR | |
803 | static ct_buffer_t conv; | 799 | static ct_buffer_t conv; | |
804 | #endif | 800 | #endif | |
805 | 801 | |||
806 | if ((fp = fopen(fname, "w")) == NULL) | 802 | if ((fp = fopen(fname, "w")) == NULL) | |
807 | return -1; | 803 | return -1; | |
808 | 804 | |||
809 | if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) | 805 | if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) | |
810 | goto done; | 806 | goto done; | |
811 | if (fputs(hist_cookie, fp) == EOF) | 807 | if (fputs(hist_cookie, fp) == EOF) | |
812 | goto done; | 808 | goto done; | |
813 | ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); | 809 | ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); | |
814 | if (ptr == NULL) | 810 | if (ptr == NULL) | |
815 | goto done; | 811 | goto done; | |
816 | for (i = 0, retval = HLAST(h, &ev); | 812 | for (i = 0, retval = HLAST(h, &ev); | |
817 | retval != -1; | 813 | retval != -1; | |
818 | retval = HPREV(h, &ev), i++) { | 814 | retval = HPREV(h, &ev), i++) { | |
819 | str = ct_encode_string(ev.str, &conv); | 815 | str = ct_encode_string(ev.str, &conv); | |
820 | len = strlen(str) * 4; | 816 | len = strlen(str) * 4; | |
821 | if (len >= max_size) { | 817 | if (len >= max_size) { | |
822 | char *nptr; | 818 | char *nptr; | |
823 | max_size = (len + 1024) & ~1023; | 819 | max_size = (len + 1024) & ~1023; | |
824 | nptr = h_realloc(ptr, max_size * sizeof(*ptr)); | 820 | nptr = h_realloc(ptr, max_size * sizeof(*ptr)); | |
825 | if (nptr == NULL) { | 821 | if (nptr == NULL) { | |
826 | i = -1; | 822 | i = -1; | |
827 | goto oomem; | 823 | goto oomem; | |
828 | } | 824 | } | |
829 | ptr = nptr; | 825 | ptr = nptr; | |
830 | } | 826 | } | |
831 | (void) strvis(ptr, str, VIS_WHITE); | 827 | (void) strvis(ptr, str, VIS_WHITE); | |
832 | (void) fprintf(fp, "%s\n", ptr); | 828 | (void) fprintf(fp, "%s\n", ptr); | |
833 | } | 829 | } | |
834 | oomem: | 830 | oomem: | |
835 | h_free(ptr); | 831 | h_free(ptr); | |
836 | done: | 832 | done: | |
837 | (void) fclose(fp); | 833 | (void) fclose(fp); | |
838 | return i; | 834 | return i; | |
839 | } | 835 | } | |
840 | 836 | |||
841 | 837 | |||
842 | /* history_prev_event(): | 838 | /* history_prev_event(): | |
843 | * Find the previous event, with number given | 839 | * Find the previous event, with number given | |
844 | */ | 840 | */ | |
845 | private int | 841 | private int | |
846 | history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) | 842 | history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) | |
847 | { | 843 | { | |
848 | int retval; | 844 | int retval; | |
849 | 845 | |||
850 | for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) | 846 | for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) | |
851 | if (ev->num == num) | 847 | if (ev->num == num) | |
852 | return 0; | 848 | return 0; | |
853 | 849 | |||
854 | he_seterrev(ev, _HE_NOT_FOUND); | 850 | he_seterrev(ev, _HE_NOT_FOUND); | |
855 | return -1; | 851 | return -1; | |
856 | } | 852 | } | |
857 | 853 | |||
858 | 854 | |||
859 | private int | 855 | private int | |
860 | history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d) | 856 | history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d) | |
861 | { | 857 | { | |
862 | int retval; | 858 | int retval; | |
863 | 859 | |||
864 | for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) | 860 | for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) | |
865 | if (ev->num == num) { | 861 | if (ev->num == num) { | |
866 | if (d) | 862 | if (d) | |
867 | *d = ((history_t *)h->h_ref)->cursor->data; | 863 | *d = ((history_t *)h->h_ref)->cursor->data; | |
868 | return 0; | 864 | return 0; | |
869 | } | 865 | } | |
870 | 866 | |||
871 | he_seterrev(ev, _HE_NOT_FOUND); | 867 | he_seterrev(ev, _HE_NOT_FOUND); | |
872 | return -1; | 868 | return -1; | |
873 | } | 869 | } | |
874 | 870 | |||
875 | 871 | |||
876 | /* history_next_event(): | 872 | /* history_next_event(): | |
877 | * Find the next event, with number given | 873 | * Find the next event, with number given | |
878 | */ | 874 | */ | |
879 | private int | 875 | private int | |
880 | history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) | 876 | history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) | |
881 | { | 877 | { | |
882 | int retval; | 878 | int retval; | |
883 | 879 | |||
884 | for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) | 880 | for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) | |
885 | if (ev->num == num) | 881 | if (ev->num == num) | |
886 | return 0; | 882 | return 0; | |
887 | 883 | |||
888 | he_seterrev(ev, _HE_NOT_FOUND); | 884 | he_seterrev(ev, _HE_NOT_FOUND); | |
889 | return -1; | 885 | return -1; | |
890 | } | 886 | } | |
891 | 887 | |||
892 | 888 | |||
893 | /* history_prev_string(): | 889 | /* history_prev_string(): | |
894 | * Find the previous event beginning with string | 890 | * Find the previous event beginning with string | |
895 | */ | 891 | */ | |
896 | private int | 892 | private int | |
897 | history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) | 893 | history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) | |
898 | { | 894 | { | |
899 | size_t len = Strlen(str); | 895 | size_t len = Strlen(str); | |
900 | int retval; | 896 | int retval; | |
901 | 897 | |||
902 | for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) | 898 | for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) | |
903 | if (Strncmp(str, ev->str, len) == 0) | 899 | if (Strncmp(str, ev->str, len) == 0) | |
904 | return 0; | 900 | return 0; | |
905 | 901 | |||
906 | he_seterrev(ev, _HE_NOT_FOUND); | 902 | he_seterrev(ev, _HE_NOT_FOUND); | |
907 | return -1; | 903 | return -1; | |
908 | } | 904 | } | |
909 | 905 | |||
910 | 906 | |||
911 | /* history_next_string(): | 907 | /* history_next_string(): | |
912 | * Find the next event beginning with string | 908 | * Find the next event beginning with string | |
913 | */ | 909 | */ | |
914 | private int | 910 | private int | |
915 | history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) | 911 | history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) | |
916 | { | 912 | { | |
917 | size_t len = Strlen(str); | 913 | size_t len = Strlen(str); | |
918 | int retval; | 914 | int retval; | |
919 | 915 | |||
920 | for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) | 916 | for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) | |
921 | if (Strncmp(str, ev->str, len) == 0) | 917 | if (Strncmp(str, ev->str, len) == 0) | |
922 | return 0; | 918 | return 0; | |
923 | 919 | |||
924 | he_seterrev(ev, _HE_NOT_FOUND); | 920 | he_seterrev(ev, _HE_NOT_FOUND); | |
925 | return -1; | 921 | return -1; | |
926 | } | 922 | } | |
927 | 923 | |||
928 | 924 | |||
929 | /* history(): | 925 | /* history(): | |
930 | * User interface to history functions. | 926 | * User interface to history functions. | |
931 | */ | 927 | */ | |
932 | int | 928 | int | |
933 | FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...) | 929 | FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...) | |
934 | { | 930 | { | |
935 | va_list va; | 931 | va_list va; | |
936 | const Char *str; | 932 | const Char *str; | |
937 | int retval; | 933 | int retval; | |
938 | 934 | |||
939 | va_start(va, fun); | 935 | va_start(va, fun); | |
940 | 936 | |||
941 | he_seterrev(ev, _HE_OK); | 937 | he_seterrev(ev, _HE_OK); | |
942 | 938 | |||
943 | switch (fun) { | 939 | switch (fun) { | |
944 | case H_GETSIZE: | 940 | case H_GETSIZE: | |
945 | retval = history_getsize(h, ev); | 941 | retval = history_getsize(h, ev); | |
946 | break; | 942 | break; | |
947 | 943 | |||
948 | case H_SETSIZE: | 944 | case H_SETSIZE: | |
949 | retval = history_setsize(h, ev, va_arg(va, int)); | 945 | retval = history_setsize(h, ev, va_arg(va, int)); | |
950 | break; | 946 | break; | |
951 | 947 | |||
952 | case H_GETUNIQUE: | 948 | case H_GETUNIQUE: | |
953 | retval = history_getunique(h, ev); | 949 | retval = history_getunique(h, ev); | |
954 | break; | 950 | break; | |
955 | 951 | |||
956 | case H_SETUNIQUE: | 952 | case H_SETUNIQUE: | |
957 | retval = history_setunique(h, ev, va_arg(va, int)); | 953 | retval = history_setunique(h, ev, va_arg(va, int)); | |
958 | break; | 954 | break; | |
959 | 955 | |||
960 | case H_ADD: | 956 | case H_ADD: | |
961 | str = va_arg(va, const Char *); | 957 | str = va_arg(va, const Char *); | |
962 | retval = HADD(h, ev, str); | 958 | retval = HADD(h, ev, str); | |
963 | break; | 959 | break; | |
964 | 960 | |||
965 | case H_DEL: | 961 | case H_DEL: | |
966 | retval = HDEL(h, ev, va_arg(va, const int)); | 962 | retval = HDEL(h, ev, va_arg(va, const int)); | |
967 | break; | 963 | break; | |
968 | 964 | |||
969 | case H_ENTER: | 965 | case H_ENTER: | |
970 | str = va_arg(va, const Char *); | 966 | str = va_arg(va, const Char *); | |
971 | if ((retval = HENTER(h, ev, str)) != -1) | 967 | if ((retval = HENTER(h, ev, str)) != -1) | |
972 | h->h_ent = ev->num; | 968 | h->h_ent = ev->num; | |
973 | break; | 969 | break; | |
974 | 970 | |||
975 | case H_APPEND: | 971 | case H_APPEND: | |
976 | str = va_arg(va, const Char *); | 972 | str = va_arg(va, const Char *); | |
977 | if ((retval = HSET(h, ev, h->h_ent)) != -1) | 973 | if ((retval = HSET(h, ev, h->h_ent)) != -1) | |
978 | retval = HADD(h, ev, str); | 974 | retval = HADD(h, ev, str); | |
979 | break; | 975 | break; | |
980 | 976 | |||
981 | case H_FIRST: | 977 | case H_FIRST: | |
982 | retval = HFIRST(h, ev); | 978 | retval = HFIRST(h, ev); | |
983 | break; | 979 | break; | |
984 | 980 | |||
985 | case H_NEXT: | 981 | case H_NEXT: | |
986 | retval = HNEXT(h, ev); | 982 | retval = HNEXT(h, ev); | |
987 | break; | 983 | break; | |
988 | 984 | |||
989 | case H_LAST: | 985 | case H_LAST: | |
990 | retval = HLAST(h, ev); | 986 | retval = HLAST(h, ev); | |
991 | break; | 987 | break; | |
992 | 988 | |||
993 | case H_PREV: | 989 | case H_PREV: | |
994 | retval = HPREV(h, ev); | 990 | retval = HPREV(h, ev); | |
995 | break; | 991 | break; | |
996 | 992 | |||
997 | case H_CURR: | 993 | case H_CURR: | |
998 | retval = HCURR(h, ev); | 994 | retval = HCURR(h, ev); | |
999 | break; | 995 | break; | |
1000 | 996 | |||
1001 | case H_SET: | 997 | case H_SET: | |
1002 | retval = HSET(h, ev, va_arg(va, const int)); | 998 | retval = HSET(h, ev, va_arg(va, const int)); | |
1003 | break; | 999 | break; | |
1004 | 1000 | |||
1005 | case H_CLEAR: | 1001 | case H_CLEAR: | |
1006 | HCLEAR(h, ev); | 1002 | HCLEAR(h, ev); | |
1007 | retval = 0; | 1003 | retval = 0; | |
1008 | break; | 1004 | break; | |
1009 | 1005 | |||
1010 | case H_LOAD: | 1006 | case H_LOAD: | |
1011 | retval = history_load(h, va_arg(va, const char *)); | 1007 | retval = history_load(h, va_arg(va, const char *)); | |
1012 | if (retval == -1) | 1008 | if (retval == -1) | |
1013 | he_seterrev(ev, _HE_HIST_READ); | 1009 | he_seterrev(ev, _HE_HIST_READ); | |
1014 | break; | 1010 | break; | |
1015 | 1011 | |||
1016 | case H_SAVE: | 1012 | case H_SAVE: | |
1017 | retval = history_save(h, va_arg(va, const char *)); | 1013 | retval = history_save(h, va_arg(va, const char *)); | |
1018 | if (retval == -1) | 1014 | if (retval == -1) | |
1019 | he_seterrev(ev, _HE_HIST_WRITE); | 1015 | he_seterrev(ev, _HE_HIST_WRITE); | |
1020 | break; | 1016 | break; | |
1021 | 1017 | |||
1022 | case H_PREV_EVENT: | 1018 | case H_PREV_EVENT: | |
1023 | retval = history_prev_event(h, ev, va_arg(va, int)); | 1019 | retval = history_prev_event(h, ev, va_arg(va, int)); | |
1024 | break; | 1020 | break; | |
1025 | 1021 | |||
1026 | case H_NEXT_EVENT: | 1022 | case H_NEXT_EVENT: | |
1027 | retval = history_next_event(h, ev, va_arg(va, int)); | 1023 | retval = history_next_event(h, ev, va_arg(va, int)); | |
1028 | break; | 1024 | break; | |
1029 | 1025 | |||
1030 | case H_PREV_STR: | 1026 | case H_PREV_STR: | |
1031 | retval = history_prev_string(h, ev, va_arg(va, const Char *)); | 1027 | retval = history_prev_string(h, ev, va_arg(va, const Char *)); | |
1032 | break; | 1028 | break; | |
1033 | 1029 | |||
1034 | case H_NEXT_STR: | 1030 | case H_NEXT_STR: | |
1035 | retval = history_next_string(h, ev, va_arg(va, const Char *)); | 1031 | retval = history_next_string(h, ev, va_arg(va, const Char *)); | |
1036 | break; | 1032 | break; | |
1037 | 1033 | |||
1038 | case H_FUNC: | 1034 | case H_FUNC: | |
1039 | { | 1035 | { | |
1040 | TYPE(History) hf; | 1036 | TYPE(History) hf; | |
1041 | 1037 | |||
1042 | hf.h_ref = va_arg(va, void *); | 1038 | hf.h_ref = va_arg(va, void *); | |
1043 | h->h_ent = -1; | 1039 | h->h_ent = -1; | |
1044 | hf.h_first = va_arg(va, history_gfun_t); | 1040 | hf.h_first = va_arg(va, history_gfun_t); | |
1045 | hf.h_next = va_arg(va, history_gfun_t); | 1041 | hf.h_next = va_arg(va, history_gfun_t); | |
1046 | hf.h_last = va_arg(va, history_gfun_t); | 1042 | hf.h_last = va_arg(va, history_gfun_t); | |
1047 | hf.h_prev = va_arg(va, history_gfun_t); | 1043 | hf.h_prev = va_arg(va, history_gfun_t); | |
1048 | hf.h_curr = va_arg(va, history_gfun_t); | 1044 | hf.h_curr = va_arg(va, history_gfun_t); | |
1049 | hf.h_set = va_arg(va, history_sfun_t); | 1045 | hf.h_set = va_arg(va, history_sfun_t); | |
1050 | hf.h_clear = va_arg(va, history_vfun_t); | 1046 | hf.h_clear = va_arg(va, history_vfun_t); | |
1051 | hf.h_enter = va_arg(va, history_efun_t); | 1047 | hf.h_enter = va_arg(va, history_efun_t); | |
1052 | hf.h_add = va_arg(va, history_efun_t); | 1048 | hf.h_add = va_arg(va, history_efun_t); | |
1053 | hf.h_del = va_arg(va, history_sfun_t); | 1049 | hf.h_del = va_arg(va, history_sfun_t); |
--- src/lib/libedit/readline.c 2011/07/29 15:16:33 1.96
+++ src/lib/libedit/readline.c 2011/07/29 20:58:07 1.97
@@ -1,2257 +1,2261 @@ | @@ -1,2257 +1,2261 @@ | |||
1 | /* $NetBSD: readline.c,v 1.96 2011/07/29 15:16:33 christos Exp $ */ | 1 | /* $NetBSD: readline.c,v 1.97 2011/07/29 20:58:07 christos Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Jaromir Dolecek. | 8 | * by Jaromir Dolecek. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include "config.h" | 32 | #include "config.h" | |
33 | #if !defined(lint) && !defined(SCCSID) | 33 | #if !defined(lint) && !defined(SCCSID) | |
34 | __RCSID("$NetBSD: readline.c,v 1.96 2011/07/29 15:16:33 christos Exp $"); | 34 | __RCSID("$NetBSD: readline.c,v 1.97 2011/07/29 20:58:07 christos Exp $"); | |
35 | #endif /* not lint && not SCCSID */ | 35 | #endif /* not lint && not SCCSID */ | |
36 | 36 | |||
37 | #include <sys/types.h> | 37 | #include <sys/types.h> | |
38 | #include <sys/stat.h> | 38 | #include <sys/stat.h> | |
39 | #include <stdio.h> | 39 | #include <stdio.h> | |
40 | #include <dirent.h> | 40 | #include <dirent.h> | |
41 | #include <string.h> | 41 | #include <string.h> | |
42 | #include <pwd.h> | 42 | #include <pwd.h> | |
43 | #include <ctype.h> | 43 | #include <ctype.h> | |
44 | #include <stdlib.h> | 44 | #include <stdlib.h> | |
45 | #include <unistd.h> | 45 | #include <unistd.h> | |
46 | #include <limits.h> | 46 | #include <limits.h> | |
47 | #include <errno.h> | 47 | #include <errno.h> | |
48 | #include <fcntl.h> | 48 | #include <fcntl.h> | |
49 | #include <setjmp.h> | 49 | #include <setjmp.h> | |
50 | #ifdef HAVE_VIS_H | |||
51 | #include <vis.h> | 50 | #include <vis.h> | |
52 | #else | 51 | ||
53 | #include "vis.h" | |||
54 | #endif | |||
55 | #include "readline/readline.h" | 52 | #include "readline/readline.h" | |
56 | #include "el.h" | 53 | #include "el.h" | |
57 | #include "fcns.h" /* for EL_NUM_FCNS */ | 54 | #include "fcns.h" /* for EL_NUM_FCNS */ | |
58 | #include "histedit.h" | 55 | #include "histedit.h" | |
59 | #include "filecomplete.h" | 56 | #include "filecomplete.h" | |
60 | 57 | |||
61 | void rl_prep_terminal(int); | 58 | void rl_prep_terminal(int); | |
62 | void rl_deprep_terminal(void); | 59 | void rl_deprep_terminal(void); | |
63 | 60 | |||
64 | /* for rl_complete() */ | 61 | /* for rl_complete() */ | |
65 | #define TAB '\r' | 62 | #define TAB '\r' | |
66 | 63 | |||
67 | /* see comment at the #ifdef for sense of this */ | 64 | /* see comment at the #ifdef for sense of this */ | |
68 | /* #define GDB_411_HACK */ | 65 | /* #define GDB_411_HACK */ | |
69 | 66 | |||
70 | /* readline compatibility stuff - look at readline sources/documentation */ | 67 | /* readline compatibility stuff - look at readline sources/documentation */ | |
71 | /* to see what these variables mean */ | 68 | /* to see what these variables mean */ | |
72 | const char *rl_library_version = "EditLine wrapper"; | 69 | const char *rl_library_version = "EditLine wrapper"; | |
73 | int rl_readline_version = RL_READLINE_VERSION; | 70 | int rl_readline_version = RL_READLINE_VERSION; | |
74 | static char empty[] = { '\0' }; | 71 | static char empty[] = { '\0' }; | |
75 | static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; | 72 | static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; | |
76 | static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', | 73 | static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', | |
77 | '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; | 74 | '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; | |
78 | char *rl_readline_name = empty; | 75 | char *rl_readline_name = empty; | |
79 | FILE *rl_instream = NULL; | 76 | FILE *rl_instream = NULL; | |
80 | FILE *rl_outstream = NULL; | 77 | FILE *rl_outstream = NULL; | |
81 | int rl_point = 0; | 78 | int rl_point = 0; | |
82 | int rl_end = 0; | 79 | int rl_end = 0; | |
83 | char *rl_line_buffer = NULL; | 80 | char *rl_line_buffer = NULL; | |
84 | VCPFunction *rl_linefunc = NULL; | 81 | VCPFunction *rl_linefunc = NULL; | |
85 | int rl_done = 0; | 82 | int rl_done = 0; | |
86 | VFunction *rl_event_hook = NULL; | 83 | VFunction *rl_event_hook = NULL; | |
87 | KEYMAP_ENTRY_ARRAY emacs_standard_keymap, | 84 | KEYMAP_ENTRY_ARRAY emacs_standard_keymap, | |
88 | emacs_meta_keymap, | 85 | emacs_meta_keymap, | |
89 | emacs_ctlx_keymap; | 86 | emacs_ctlx_keymap; | |
90 | 87 | |||
91 | int history_base = 1; /* probably never subject to change */ | 88 | int history_base = 1; /* probably never subject to change */ | |
92 | int history_length = 0; | 89 | int history_length = 0; | |
93 | int max_input_history = 0; | 90 | int max_input_history = 0; | |
94 | char history_expansion_char = '!'; | 91 | char history_expansion_char = '!'; | |
95 | char history_subst_char = '^'; | 92 | char history_subst_char = '^'; | |
96 | char *history_no_expand_chars = expand_chars; | 93 | char *history_no_expand_chars = expand_chars; | |
97 | Function *history_inhibit_expansion_function = NULL; | 94 | Function *history_inhibit_expansion_function = NULL; | |
98 | char *history_arg_extract(int start, int end, const char *str); | 95 | char *history_arg_extract(int start, int end, const char *str); | |
99 | 96 | |||
100 | int rl_inhibit_completion = 0; | 97 | int rl_inhibit_completion = 0; | |
101 | int rl_attempted_completion_over = 0; | 98 | int rl_attempted_completion_over = 0; | |
102 | char *rl_basic_word_break_characters = break_chars; | 99 | char *rl_basic_word_break_characters = break_chars; | |
103 | char *rl_completer_word_break_characters = NULL; | 100 | char *rl_completer_word_break_characters = NULL; | |
104 | char *rl_completer_quote_characters = NULL; | 101 | char *rl_completer_quote_characters = NULL; | |
105 | Function *rl_completion_entry_function = NULL; | 102 | Function *rl_completion_entry_function = NULL; | |
106 | CPPFunction *rl_attempted_completion_function = NULL; | 103 | CPPFunction *rl_attempted_completion_function = NULL; | |
107 | Function *rl_pre_input_hook = NULL; | 104 | Function *rl_pre_input_hook = NULL; | |
108 | Function *rl_startup1_hook = NULL; | 105 | Function *rl_startup1_hook = NULL; | |
109 | int (*rl_getc_function)(FILE *) = NULL; | 106 | int (*rl_getc_function)(FILE *) = NULL; | |
110 | char *rl_terminal_name = NULL; | 107 | char *rl_terminal_name = NULL; | |
111 | int rl_already_prompted = 0; | 108 | int rl_already_prompted = 0; | |
112 | int rl_filename_completion_desired = 0; | 109 | int rl_filename_completion_desired = 0; | |
113 | int rl_ignore_completion_duplicates = 0; | 110 | int rl_ignore_completion_duplicates = 0; | |
114 | int rl_catch_signals = 1; | 111 | int rl_catch_signals = 1; | |
115 | int readline_echoing_p = 1; | 112 | int readline_echoing_p = 1; | |
116 | int _rl_print_completions_horizontally = 0; | 113 | int _rl_print_completions_horizontally = 0; | |
117 | VFunction *rl_redisplay_function = NULL; | 114 | VFunction *rl_redisplay_function = NULL; | |
118 | Function *rl_startup_hook = NULL; | 115 | Function *rl_startup_hook = NULL; | |
119 | VFunction *rl_completion_display_matches_hook = NULL; | 116 | VFunction *rl_completion_display_matches_hook = NULL; | |
120 | VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; | 117 | VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; | |
121 | VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; | 118 | VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; | |
122 | KEYMAP_ENTRY_ARRAY emacs_meta_keymap; | 119 | KEYMAP_ENTRY_ARRAY emacs_meta_keymap; | |
123 | 120 | |||
124 | /* | 121 | /* | |
125 | * The current prompt string. | 122 | * The current prompt string. | |
126 | */ | 123 | */ | |
127 | char *rl_prompt = NULL; | 124 | char *rl_prompt = NULL; | |
128 | /* | 125 | /* | |
129 | * This is set to character indicating type of completion being done by | 126 | * This is set to character indicating type of completion being done by | |
130 | * rl_complete_internal(); this is available for application completion | 127 | * rl_complete_internal(); this is available for application completion | |
131 | * functions. | 128 | * functions. | |
132 | */ | 129 | */ | |
133 | int rl_completion_type = 0; | 130 | int rl_completion_type = 0; | |
134 | 131 | |||
135 | /* | 132 | /* | |
136 | * If more than this number of items results from query for possible | 133 | * If more than this number of items results from query for possible | |
137 | * completions, we ask user if they are sure to really display the list. | 134 | * completions, we ask user if they are sure to really display the list. | |
138 | */ | 135 | */ | |
139 | int rl_completion_query_items = 100; | 136 | int rl_completion_query_items = 100; | |
140 | 137 | |||
141 | /* | 138 | /* | |
142 | * List of characters which are word break characters, but should be left | 139 | * List of characters which are word break characters, but should be left | |
143 | * in the parsed text when it is passed to the completion function. | 140 | * in the parsed text when it is passed to the completion function. | |
144 | * Shell uses this to help determine what kind of completing to do. | 141 | * Shell uses this to help determine what kind of completing to do. | |
145 | */ | 142 | */ | |
146 | char *rl_special_prefixes = NULL; | 143 | char *rl_special_prefixes = NULL; | |
147 | 144 | |||
148 | /* | 145 | /* | |
149 | * This is the character appended to the completed words if at the end of | 146 | * This is the character appended to the completed words if at the end of | |
150 | * the line. Default is ' ' (a space). | 147 | * the line. Default is ' ' (a space). | |
151 | */ | 148 | */ | |
152 | int rl_completion_append_character = ' '; | 149 | int rl_completion_append_character = ' '; | |
153 | 150 | |||
154 | /* stuff below is used internally by libedit for readline emulation */ | 151 | /* stuff below is used internally by libedit for readline emulation */ | |
155 | 152 | |||
156 | static History *h = NULL; | 153 | static History *h = NULL; | |
157 | static EditLine *e = NULL; | 154 | static EditLine *e = NULL; | |
158 | static Function *map[256]; | 155 | static Function *map[256]; | |
159 | static jmp_buf topbuf; | 156 | static jmp_buf topbuf; | |
160 | 157 | |||
161 | /* internal functions */ | 158 | /* internal functions */ | |
162 | static unsigned char _el_rl_complete(EditLine *, int); | 159 | static unsigned char _el_rl_complete(EditLine *, int); | |
163 | static unsigned char _el_rl_tstp(EditLine *, int); | 160 | static unsigned char _el_rl_tstp(EditLine *, int); | |
164 | static char *_get_prompt(EditLine *); | 161 | static char *_get_prompt(EditLine *); | |
165 | static int _getc_function(EditLine *, char *); | 162 | static int _getc_function(EditLine *, char *); | |
166 | static HIST_ENTRY *_move_history(int); | 163 | static HIST_ENTRY *_move_history(int); | |
167 | static int _history_expand_command(const char *, size_t, size_t, | 164 | static int _history_expand_command(const char *, size_t, size_t, | |
168 | char **); | 165 | char **); | |
169 | static char *_rl_compat_sub(const char *, const char *, | 166 | static char *_rl_compat_sub(const char *, const char *, | |
170 | const char *, int); | 167 | const char *, int); | |
171 | static int _rl_event_read_char(EditLine *, char *); | 168 | static int _rl_event_read_char(EditLine *, char *); | |
172 | static void _rl_update_pos(void); | 169 | static void _rl_update_pos(void); | |
173 | 170 | |||
174 | 171 | |||
175 | /* ARGSUSED */ | 172 | /* ARGSUSED */ | |
176 | static char * | 173 | static char * | |
177 | _get_prompt(EditLine *el __attribute__((__unused__))) | 174 | _get_prompt(EditLine *el __attribute__((__unused__))) | |
178 | { | 175 | { | |
179 | rl_already_prompted = 1; | 176 | rl_already_prompted = 1; | |
180 | return rl_prompt; | 177 | return rl_prompt; | |
181 | } | 178 | } | |
182 | 179 | |||
183 | 180 | |||
184 | /* | 181 | /* | |
185 | * generic function for moving around history | 182 | * generic function for moving around history | |
186 | */ | 183 | */ | |
187 | static HIST_ENTRY * | 184 | static HIST_ENTRY * | |
188 | _move_history(int op) | 185 | _move_history(int op) | |
189 | { | 186 | { | |
190 | HistEvent ev; | 187 | HistEvent ev; | |
191 | static HIST_ENTRY rl_he; | 188 | static HIST_ENTRY rl_he; | |
192 | 189 | |||
193 | if (history(h, &ev, op) != 0) | 190 | if (history(h, &ev, op) != 0) | |
194 | return NULL; | 191 | return NULL; | |
195 | 192 | |||
196 | rl_he.line = ev.str; | 193 | rl_he.line = ev.str; | |
197 | rl_he.data = NULL; | 194 | rl_he.data = NULL; | |
198 | 195 | |||
199 | return &rl_he; | 196 | return &rl_he; | |
200 | } | 197 | } | |
201 | 198 | |||
202 | 199 | |||
203 | /* | 200 | /* | |
204 | * read one key from user defined input function | 201 | * read one key from user defined input function | |
205 | */ | 202 | */ | |
206 | static int | 203 | static int | |
207 | /*ARGSUSED*/ | 204 | /*ARGSUSED*/ | |
208 | _getc_function(EditLine *el, char *c) | 205 | _getc_function(EditLine *el __attribute__((__unused__)), char *c) | |
209 | { | 206 | { | |
210 | int i; | 207 | int i; | |
211 | 208 | |||
212 | i = (*rl_getc_function)(NULL); | 209 | i = (*rl_getc_function)(NULL); | |
213 | if (i == -1) | 210 | if (i == -1) | |
214 | return 0; | 211 | return 0; | |
215 | *c = i; | 212 | *c = i; | |
216 | return 1; | 213 | return 1; | |
217 | } | 214 | } | |
218 | 215 | |||
219 | static void | 216 | static void | |
220 | _resize_fun(EditLine *el, void *a) | 217 | _resize_fun(EditLine *el, void *a) | |
221 | { | 218 | { | |
222 | const LineInfo *li; | 219 | const LineInfo *li; | |
223 | char **ap = a; | 220 | char **ap = a; | |
224 | 221 | |||
225 | li = el_line(el); | 222 | li = el_line(el); | |
226 | /* a cheesy way to get rid of const cast. */ | 223 | /* a cheesy way to get rid of const cast. */ | |
227 | *ap = memchr(li->buffer, *li->buffer, 1); | 224 | *ap = memchr(li->buffer, *li->buffer, 1); | |
228 | } | 225 | } | |
229 | 226 | |||
230 | static const char _dothistory[] = "/.history"; | 227 | static const char _dothistory[] = "/.history"; | |
231 | 228 | |||
232 | static const char * | 229 | static const char * | |
233 | _default_history_file(void) | 230 | _default_history_file(void) | |
234 | { | 231 | { | |
235 | struct passwd *p; | 232 | struct passwd *p; | |
236 | static char path[PATH_MAX]; | 233 | static char path[PATH_MAX]; | |
237 | 234 | |||
238 | if (*path) | 235 | if (*path) | |
239 | return path; | 236 | return path; | |
240 | if ((p = getpwuid(getuid())) == NULL) | 237 | if ((p = getpwuid(getuid())) == NULL) | |
241 | return NULL; | 238 | return NULL; | |
242 | strlcpy(path, p->pw_dir, PATH_MAX); | 239 | strlcpy(path, p->pw_dir, PATH_MAX); | |
243 | strlcat(path, _dothistory, PATH_MAX); | 240 | strlcat(path, _dothistory, PATH_MAX); | |
244 | return path; | 241 | return path; | |
245 | } | 242 | } | |
246 | 243 | |||
247 | /* | 244 | /* | |
248 | * READLINE compatibility stuff | 245 | * READLINE compatibility stuff | |
249 | */ | 246 | */ | |
250 | 247 | |||
251 | /* | 248 | /* | |
252 | * Set the prompt | 249 | * Set the prompt | |
253 | */ | 250 | */ | |
254 | int | 251 | int | |
255 | rl_set_prompt(const char *prompt) | 252 | rl_set_prompt(const char *prompt) | |
256 | { | 253 | { | |
257 | char *p; | 254 | char *p; | |
258 | 255 | |||
259 | if (!prompt) | 256 | if (!prompt) | |
260 | prompt = ""; | 257 | prompt = ""; | |
261 | if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) | 258 | if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) | |
262 | return 0; | 259 | return 0; | |
263 | if (rl_prompt) | 260 | if (rl_prompt) | |
264 | el_free(rl_prompt); | 261 | el_free(rl_prompt); | |
265 | rl_prompt = strdup(prompt); | 262 | rl_prompt = strdup(prompt); | |
266 | if (rl_prompt == NULL) | 263 | if (rl_prompt == NULL) | |
267 | return -1; | 264 | return -1; | |
268 | 265 | |||
269 | while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) | 266 | while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) | |
270 | *p = RL_PROMPT_START_IGNORE; | 267 | *p = RL_PROMPT_START_IGNORE; | |
271 | 268 | |||
272 | return 0; | 269 | return 0; | |
273 | } | 270 | } | |
274 | 271 | |||
275 | /* | 272 | /* | |
276 | * initialize rl compat stuff | 273 | * initialize rl compat stuff | |
277 | */ | 274 | */ | |
278 | int | 275 | int | |
279 | rl_initialize(void) | 276 | rl_initialize(void) | |
280 | { | 277 | { | |
281 | HistEvent ev; | 278 | HistEvent ev; | |
282 | int editmode = 1; | 279 | int editmode = 1; | |
283 | struct termios t; | 280 | struct termios t; | |
284 | 281 | |||
285 | if (e != NULL) | 282 | if (e != NULL) | |
286 | el_end(e); | 283 | el_end(e); | |
287 | if (h != NULL) | 284 | if (h != NULL) | |
288 | history_end(h); | 285 | history_end(h); | |
289 | 286 | |||
290 | if (!rl_instream) | 287 | if (!rl_instream) | |
291 | rl_instream = stdin; | 288 | rl_instream = stdin; | |
292 | if (!rl_outstream) | 289 | if (!rl_outstream) | |
293 | rl_outstream = stdout; | 290 | rl_outstream = stdout; | |
294 | 291 | |||
295 | /* | 292 | /* | |
296 | * See if we don't really want to run the editor | 293 | * See if we don't really want to run the editor | |
297 | */ | 294 | */ | |
298 | if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) | 295 | if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) | |
299 | editmode = 0; | 296 | editmode = 0; | |
300 | 297 | |||
301 | e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); | 298 | e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); | |
302 | 299 | |||
303 | if (!editmode) | 300 | if (!editmode) | |
304 | el_set(e, EL_EDITMODE, 0); | 301 | el_set(e, EL_EDITMODE, 0); | |
305 | 302 | |||
306 | h = history_init(); | 303 | h = history_init(); | |
307 | if (!e || !h) | 304 | if (!e || !h) | |
308 | return -1; | 305 | return -1; | |
309 | 306 | |||
310 | history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ | 307 | history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ | |
311 | history_length = 0; | 308 | history_length = 0; | |
312 | max_input_history = INT_MAX; | 309 | max_input_history = INT_MAX; | |
313 | el_set(e, EL_HIST, history, h); | 310 | el_set(e, EL_HIST, history, h); | |
314 | 311 | |||
315 | /* Setup resize function */ | 312 | /* Setup resize function */ | |
316 | el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer); | 313 | el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer); | |
317 | 314 | |||
318 | /* setup getc function if valid */ | 315 | /* setup getc function if valid */ | |
319 | if (rl_getc_function) | 316 | if (rl_getc_function) | |
320 | el_set(e, EL_GETCFN, _getc_function); | 317 | el_set(e, EL_GETCFN, _getc_function); | |
321 | 318 | |||
322 | /* for proper prompt printing in readline() */ | 319 | /* for proper prompt printing in readline() */ | |
323 | if (rl_set_prompt("") == -1) { | 320 | if (rl_set_prompt("") == -1) { | |
324 | history_end(h); | 321 | history_end(h); | |
325 | el_end(e); | 322 | el_end(e); | |
326 | return -1; | 323 | return -1; | |
327 | } | 324 | } | |
328 | el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); | 325 | el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); | |
329 | el_set(e, EL_SIGNAL, rl_catch_signals); | 326 | el_set(e, EL_SIGNAL, rl_catch_signals); | |
330 | 327 | |||
331 | /* set default mode to "emacs"-style and read setting afterwards */ | 328 | /* set default mode to "emacs"-style and read setting afterwards */ | |
332 | /* so this can be overriden */ | 329 | /* so this can be overriden */ | |
333 | el_set(e, EL_EDITOR, "emacs"); | 330 | el_set(e, EL_EDITOR, "emacs"); | |
334 | if (rl_terminal_name != NULL) | 331 | if (rl_terminal_name != NULL) | |
335 | el_set(e, EL_TERMINAL, rl_terminal_name); | 332 | el_set(e, EL_TERMINAL, rl_terminal_name); | |
336 | else | 333 | else | |
337 | el_get(e, EL_TERMINAL, &rl_terminal_name); | 334 | el_get(e, EL_TERMINAL, &rl_terminal_name); | |
338 | 335 | |||
339 | /* | 336 | /* | |
340 | * Word completion - this has to go AFTER rebinding keys | 337 | * Word completion - this has to go AFTER rebinding keys | |
341 | * to emacs-style. | 338 | * to emacs-style. | |
342 | */ | 339 | */ | |
343 | el_set(e, EL_ADDFN, "rl_complete", | 340 | el_set(e, EL_ADDFN, "rl_complete", | |
344 | "ReadLine compatible completion function", | 341 | "ReadLine compatible completion function", | |
345 | _el_rl_complete); | 342 | _el_rl_complete); | |
346 | el_set(e, EL_BIND, "^I", "rl_complete", NULL); | 343 | el_set(e, EL_BIND, "^I", "rl_complete", NULL); | |
347 | 344 | |||
348 | /* | 345 | /* | |
349 | * Send TSTP when ^Z is pressed. | 346 | * Send TSTP when ^Z is pressed. | |
350 | */ | 347 | */ | |
351 | el_set(e, EL_ADDFN, "rl_tstp", | 348 | el_set(e, EL_ADDFN, "rl_tstp", | |
352 | "ReadLine compatible suspend function", | 349 | "ReadLine compatible suspend function", | |
353 | _el_rl_tstp); | 350 | _el_rl_tstp); | |
354 | el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); | 351 | el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); | |
355 | 352 | |||
356 | /* read settings from configuration file */ | 353 | /* read settings from configuration file */ | |
357 | el_source(e, NULL); | 354 | el_source(e, NULL); | |
358 | 355 | |||
359 | /* | 356 | /* | |
360 | * Unfortunately, some applications really do use rl_point | 357 | * Unfortunately, some applications really do use rl_point | |
361 | * and rl_line_buffer directly. | 358 | * and rl_line_buffer directly. | |
362 | */ | 359 | */ | |
363 | _resize_fun(e, &rl_line_buffer); | 360 | _resize_fun(e, &rl_line_buffer); | |
364 | _rl_update_pos(); | 361 | _rl_update_pos(); | |
365 | 362 | |||
366 | if (rl_startup_hook) | 363 | if (rl_startup_hook) | |
367 | (*rl_startup_hook)(NULL, 0); | 364 | (*rl_startup_hook)(NULL, 0); | |
368 | 365 | |||
369 | return 0; | 366 | return 0; | |
370 | } | 367 | } | |
371 | 368 | |||
372 | 369 | |||
373 | /* | 370 | /* | |
374 | * read one line from input stream and return it, chomping | 371 | * read one line from input stream and return it, chomping | |
375 | * trailing newline (if there is any) | 372 | * trailing newline (if there is any) | |
376 | */ | 373 | */ | |
377 | char * | 374 | char * | |
378 | readline(const char *p) | 375 | readline(const char *p) | |
379 | { | 376 | { | |
380 | HistEvent ev; | 377 | HistEvent ev; | |
381 | const char * volatile prompt = p; | 378 | const char * volatile prompt = p; | |
382 | int count; | 379 | int count; | |
383 | const char *ret; | 380 | const char *ret; | |
384 | char *buf; | 381 | char *buf; | |
385 | static int used_event_hook; | 382 | static int used_event_hook; | |
386 | 383 | |||
387 | if (e == NULL || h == NULL) | 384 | if (e == NULL || h == NULL) | |
388 | rl_initialize(); | 385 | rl_initialize(); | |
389 | 386 | |||
390 | rl_done = 0; | 387 | rl_done = 0; | |
391 | 388 | |||
392 | (void)setjmp(topbuf); | 389 | (void)setjmp(topbuf); | |
393 | 390 | |||
394 | /* update prompt accordingly to what has been passed */ | 391 | /* update prompt accordingly to what has been passed */ | |
395 | if (rl_set_prompt(prompt) == -1) | 392 | if (rl_set_prompt(prompt) == -1) | |
396 | return NULL; | 393 | return NULL; | |
397 | 394 | |||
398 | if (rl_pre_input_hook) | 395 | if (rl_pre_input_hook) | |
399 | (*rl_pre_input_hook)(NULL, 0); | 396 | (*rl_pre_input_hook)(NULL, 0); | |
400 | 397 | |||
401 | if (rl_event_hook && !(e->el_flags&NO_TTY)) { | 398 | if (rl_event_hook && !(e->el_flags&NO_TTY)) { | |
402 | el_set(e, EL_GETCFN, _rl_event_read_char); | 399 | el_set(e, EL_GETCFN, _rl_event_read_char); | |
403 | used_event_hook = 1; | 400 | used_event_hook = 1; | |
404 | } | 401 | } | |
405 | 402 | |||
406 | if (!rl_event_hook && used_event_hook) { | 403 | if (!rl_event_hook && used_event_hook) { | |
407 | el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); | 404 | el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); | |
408 | used_event_hook = 0; | 405 | used_event_hook = 0; | |
409 | } | 406 | } | |
410 | 407 | |||
411 | rl_already_prompted = 0; | 408 | rl_already_prompted = 0; | |
412 | 409 | |||
413 | /* get one line from input stream */ | 410 | /* get one line from input stream */ | |
414 | ret = el_gets(e, &count); | 411 | ret = el_gets(e, &count); | |
415 | 412 | |||
416 | if (ret && count > 0) { | 413 | if (ret && count > 0) { | |
417 | int lastidx; | 414 | int lastidx; | |
418 | 415 | |||
419 | buf = strdup(ret); | 416 | buf = strdup(ret); | |
420 | if (buf == NULL) | 417 | if (buf == NULL) | |
421 | return NULL; | 418 | return NULL; | |
422 | lastidx = count - 1; | 419 | lastidx = count - 1; | |
423 | if (buf[lastidx] == '\n') | 420 | if (buf[lastidx] == '\n') | |
424 | buf[lastidx] = '\0'; | 421 | buf[lastidx] = '\0'; | |
425 | } else | 422 | } else | |
426 | buf = NULL; | 423 | buf = NULL; | |
427 | 424 | |||
428 | history(h, &ev, H_GETSIZE); | 425 | history(h, &ev, H_GETSIZE); | |
429 | history_length = ev.num; | 426 | history_length = ev.num; | |
430 | 427 | |||
431 | return buf; | 428 | return buf; | |
432 | } | 429 | } | |
433 | 430 | |||
434 | /* | 431 | /* | |
435 | * history functions | 432 | * history functions | |
436 | */ | 433 | */ | |
437 | 434 | |||
438 | /* | 435 | /* | |
439 | * is normally called before application starts to use | 436 | * is normally called before application starts to use | |
440 | * history expansion functions | 437 | * history expansion functions | |
441 | */ | 438 | */ | |
442 | void | 439 | void | |
443 | using_history(void) | 440 | using_history(void) | |
444 | { | 441 | { | |
445 | if (h == NULL || e == NULL) | 442 | if (h == NULL || e == NULL) | |
446 | rl_initialize(); | 443 | rl_initialize(); | |
447 | } | 444 | } | |
448 | 445 | |||
449 | 446 | |||
450 | /* | 447 | /* | |
451 | * substitute ``what'' with ``with'', returning resulting string; if | 448 | * substitute ``what'' with ``with'', returning resulting string; if | |
452 | * globally == 1, substitutes all occurrences of what, otherwise only the | 449 | * globally == 1, substitutes all occurrences of what, otherwise only the | |
453 | * first one | 450 | * first one | |
454 | */ | 451 | */ | |
455 | static char * | 452 | static char * | |
456 | _rl_compat_sub(const char *str, const char *what, const char *with, | 453 | _rl_compat_sub(const char *str, const char *what, const char *with, | |
457 | int globally) | 454 | int globally) | |
458 | { | 455 | { | |
459 | const char *s; | 456 | const char *s; | |
460 | char *r, *result; | 457 | char *r, *result; | |
461 | size_t len, with_len, what_len; | 458 | size_t len, with_len, what_len; | |
462 | 459 | |||
463 | len = strlen(str); | 460 | len = strlen(str); | |
464 | with_len = strlen(with); | 461 | with_len = strlen(with); | |
465 | what_len = strlen(what); | 462 | what_len = strlen(what); | |
466 | 463 | |||
467 | /* calculate length we need for result */ | 464 | /* calculate length we need for result */ | |
468 | s = str; | 465 | s = str; | |
469 | while (*s) { | 466 | while (*s) { | |
470 | if (*s == *what && !strncmp(s, what, what_len)) { | 467 | if (*s == *what && !strncmp(s, what, what_len)) { | |
471 | len += with_len - what_len; | 468 | len += with_len - what_len; | |
472 | if (!globally) | 469 | if (!globally) | |
473 | break; | 470 | break; | |
474 | s += what_len; | 471 | s += what_len; | |
475 | } else | 472 | } else | |
476 | s++; | 473 | s++; | |
477 | } | 474 | } | |
478 | r = result = el_malloc((len + 1) * sizeof(*r)); | 475 | r = result = el_malloc((len + 1) * sizeof(*r)); | |
479 | if (result == NULL) | 476 | if (result == NULL) | |
480 | return NULL; | 477 | return NULL; | |
481 | s = str; | 478 | s = str; | |
482 | while (*s) { | 479 | while (*s) { | |
483 | if (*s == *what && !strncmp(s, what, what_len)) { | 480 | if (*s == *what && !strncmp(s, what, what_len)) { | |
484 | (void)strncpy(r, with, with_len); | 481 | (void)strncpy(r, with, with_len); | |
485 | r += with_len; | 482 | r += with_len; | |
486 | s += what_len; | 483 | s += what_len; | |
487 | if (!globally) { | 484 | if (!globally) { | |
488 | (void)strcpy(r, s); | 485 | (void)strcpy(r, s); | |
489 | return result; | 486 | return result; | |
490 | } | 487 | } | |
491 | } else | 488 | } else | |
492 | *r++ = *s++; | 489 | *r++ = *s++; | |
493 | } | 490 | } | |
494 | *r = '\0'; | 491 | *r = '\0'; | |
495 | return result; | 492 | return result; | |
496 | } | 493 | } | |
497 | 494 | |||
498 | static char *last_search_pat; /* last !?pat[?] search pattern */ | 495 | static char *last_search_pat; /* last !?pat[?] search pattern */ | |
499 | static char *last_search_match; /* last !?pat[?] that matched */ | 496 | static char *last_search_match; /* last !?pat[?] that matched */ | |
500 | 497 | |||
501 | const char * | 498 | const char * | |
502 | get_history_event(const char *cmd, int *cindex, int qchar) | 499 | get_history_event(const char *cmd, int *cindex, int qchar) | |
503 | { | 500 | { | |
504 | int idx, sign, sub, num, begin, ret; | 501 | int idx, sign, sub, num, begin, ret; | |
505 | size_t len; | 502 | size_t len; | |
506 | char *pat; | 503 | char *pat; | |
507 | const char *rptr; | 504 | const char *rptr; | |
508 | HistEvent ev; | 505 | HistEvent ev; | |
509 | 506 | |||
510 | idx = *cindex; | 507 | idx = *cindex; | |
511 | if (cmd[idx++] != history_expansion_char) | 508 | if (cmd[idx++] != history_expansion_char) | |
512 | return NULL; | 509 | return NULL; | |
513 | 510 | |||
514 | /* find out which event to take */ | 511 | /* find out which event to take */ | |
515 | if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') { | 512 | if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') { | |
516 | if (history(h, &ev, H_FIRST) != 0) | 513 | if (history(h, &ev, H_FIRST) != 0) | |
517 | return NULL; | 514 | return NULL; | |
518 | *cindex = cmd[idx]? (idx + 1):idx; | 515 | *cindex = cmd[idx]? (idx + 1):idx; | |
519 | return ev.str; | 516 | return ev.str; | |
520 | } | 517 | } | |
521 | sign = 0; | 518 | sign = 0; | |
522 | if (cmd[idx] == '-') { | 519 | if (cmd[idx] == '-') { | |
523 | sign = 1; | 520 | sign = 1; | |
524 | idx++; | 521 | idx++; | |
525 | } | 522 | } | |
526 | 523 | |||
527 | if ('0' <= cmd[idx] && cmd[idx] <= '9') { | 524 | if ('0' <= cmd[idx] && cmd[idx] <= '9') { | |
528 | HIST_ENTRY *rl_he; | 525 | HIST_ENTRY *rl_he; | |
529 | 526 | |||
530 | num = 0; | 527 | num = 0; | |
531 | while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { | 528 | while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { | |
532 | num = num * 10 + cmd[idx] - '0'; | 529 | num = num * 10 + cmd[idx] - '0'; | |
533 | idx++; | 530 | idx++; | |
534 | } | 531 | } | |
535 | if (sign) | 532 | if (sign) | |
536 | num = history_length - num + 1; | 533 | num = history_length - num + 1; | |
537 | 534 | |||
538 | if (!(rl_he = history_get(num))) | 535 | if (!(rl_he = history_get(num))) | |
539 | return NULL; | 536 | return NULL; | |
540 | 537 | |||
541 | *cindex = idx; | 538 | *cindex = idx; | |
542 | return rl_he->line; | 539 | return rl_he->line; | |
543 | } | 540 | } | |
544 | sub = 0; | 541 | sub = 0; | |
545 | if (cmd[idx] == '?') { | 542 | if (cmd[idx] == '?') { | |
546 | sub = 1; | 543 | sub = 1; | |
547 | idx++; | 544 | idx++; | |
548 | } | 545 | } | |
549 | begin = idx; | 546 | begin = idx; | |
550 | while (cmd[idx]) { | 547 | while (cmd[idx]) { | |
551 | if (cmd[idx] == '\n') | 548 | if (cmd[idx] == '\n') | |
552 | break; | 549 | break; | |
553 | if (sub && cmd[idx] == '?') | 550 | if (sub && cmd[idx] == '?') | |
554 | break; | 551 | break; | |
555 | if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' | 552 | if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' | |
556 | || cmd[idx] == '\t' || cmd[idx] == qchar)) | 553 | || cmd[idx] == '\t' || cmd[idx] == qchar)) | |
557 | break; | 554 | break; | |
558 | idx++; | 555 | idx++; | |
559 | } | 556 | } | |
560 | len = idx - begin; | 557 | len = idx - begin; | |
561 | if (sub && cmd[idx] == '?') | 558 | if (sub && cmd[idx] == '?') | |
562 | idx++; | 559 | idx++; | |
563 | if (sub && len == 0 && last_search_pat && *last_search_pat) | 560 | if (sub && len == 0 && last_search_pat && *last_search_pat) | |
564 | pat = last_search_pat; | 561 | pat = last_search_pat; | |
565 | else if (len == 0) | 562 | else if (len == 0) | |
566 | return NULL; | 563 | return NULL; | |
567 | else { | 564 | else { | |
568 | if ((pat = el_malloc((len + 1) * sizeof(*pat))) == NULL) | 565 | if ((pat = el_malloc((len + 1) * sizeof(*pat))) == NULL) | |
569 | return NULL; | 566 | return NULL; | |
570 | (void)strncpy(pat, cmd + begin, len); | 567 | (void)strncpy(pat, cmd + begin, len); | |
571 | pat[len] = '\0'; | 568 | pat[len] = '\0'; | |
572 | } | 569 | } | |
573 | 570 | |||
574 | if (history(h, &ev, H_CURR) != 0) { | 571 | if (history(h, &ev, H_CURR) != 0) { | |
575 | if (pat != last_search_pat) | 572 | if (pat != last_search_pat) | |
576 | el_free(pat); | 573 | el_free(pat); | |
577 | return NULL; | 574 | return NULL; | |
578 | } | 575 | } | |
579 | num = ev.num; | 576 | num = ev.num; | |
580 | 577 | |||
581 | if (sub) { | 578 | if (sub) { | |
582 | if (pat != last_search_pat) { | 579 | if (pat != last_search_pat) { | |
583 | if (last_search_pat) | 580 | if (last_search_pat) | |
584 | el_free(last_search_pat); | 581 | el_free(last_search_pat); | |
585 | last_search_pat = pat; | 582 | last_search_pat = pat; | |
586 | } | 583 | } | |
587 | ret = history_search(pat, -1); | 584 | ret = history_search(pat, -1); | |
588 | } else | 585 | } else | |
589 | ret = history_search_prefix(pat, -1); | 586 | ret = history_search_prefix(pat, -1); | |
590 | 587 | |||
591 | if (ret == -1) { | 588 | if (ret == -1) { | |
592 | /* restore to end of list on failed search */ | 589 | /* restore to end of list on failed search */ | |
593 | history(h, &ev, H_FIRST); | 590 | history(h, &ev, H_FIRST); | |
594 | (void)fprintf(rl_outstream, "%s: Event not found\n", pat); | 591 | (void)fprintf(rl_outstream, "%s: Event not found\n", pat); | |
595 | if (pat != last_search_pat) | 592 | if (pat != last_search_pat) | |
596 | el_free(pat); | 593 | el_free(pat); | |
597 | return NULL; | 594 | return NULL; | |
598 | } | 595 | } | |
599 | 596 | |||
600 | if (sub && len) { | 597 | if (sub && len) { | |
601 | if (last_search_match && last_search_match != pat) | 598 | if (last_search_match && last_search_match != pat) | |
602 | el_free(last_search_match); | 599 | el_free(last_search_match); | |
603 | last_search_match = pat; | 600 | last_search_match = pat; | |
604 | } | 601 | } | |
605 | 602 | |||
606 | if (pat != last_search_pat) | 603 | if (pat != last_search_pat) | |
607 | el_free(pat); | 604 | el_free(pat); | |
608 | 605 | |||
609 | if (history(h, &ev, H_CURR) != 0) | 606 | if (history(h, &ev, H_CURR) != 0) | |
610 | return NULL; | 607 | return NULL; | |
611 | *cindex = idx; | 608 | *cindex = idx; | |
612 | rptr = ev.str; | 609 | rptr = ev.str; | |
613 | 610 | |||
614 | /* roll back to original position */ | 611 | /* roll back to original position */ | |
615 | (void)history(h, &ev, H_SET, num); | 612 | (void)history(h, &ev, H_SET, num); | |
616 | 613 | |||
617 | return rptr; | 614 | return rptr; | |
618 | } | 615 | } | |
619 | 616 | |||
620 | /* | 617 | /* | |
621 | * the real function doing history expansion - takes as argument command | 618 | * the real function doing history expansion - takes as argument command | |
622 | * to do and data upon which the command should be executed | 619 | * to do and data upon which the command should be executed | |
623 | * does expansion the way I've understood readline documentation | 620 | * does expansion the way I've understood readline documentation | |
624 | * | 621 | * | |
625 | * returns 0 if data was not modified, 1 if it was and 2 if the string | 622 | * returns 0 if data was not modified, 1 if it was and 2 if the string | |
626 | * should be only printed and not executed; in case of error, | 623 | * should be only printed and not executed; in case of error, | |
627 | * returns -1 and *result points to NULL | 624 | * returns -1 and *result points to NULL | |
628 | * it's callers responsibility to free() string returned in *result | 625 | * it's callers responsibility to free() string returned in *result | |
629 | */ | 626 | */ | |
630 | static int | 627 | static int | |
631 | _history_expand_command(const char *command, size_t offs, size_t cmdlen, | 628 | _history_expand_command(const char *command, size_t offs, size_t cmdlen, | |
632 | char **result) | 629 | char **result) | |
633 | { | 630 | { | |
634 | char *tmp, *search = NULL, *aptr; | 631 | char *tmp, *search = NULL, *aptr; | |
635 | const char *ptr, *cmd; | 632 | const char *ptr, *cmd; | |
636 | static char *from = NULL, *to = NULL; | 633 | static char *from = NULL, *to = NULL; | |
637 | int start, end, idx, has_mods = 0; | 634 | int start, end, idx, has_mods = 0; | |
638 | int p_on = 0, g_on = 0; | 635 | int p_on = 0, g_on = 0; | |
639 | 636 | |||
640 | *result = NULL; | 637 | *result = NULL; | |
641 | aptr = NULL; | 638 | aptr = NULL; | |
642 | ptr = NULL; | 639 | ptr = NULL; | |
643 | 640 | |||
644 | /* First get event specifier */ | 641 | /* First get event specifier */ | |
645 | idx = 0; | 642 | idx = 0; | |
646 | 643 | |||
647 | if (strchr(":^*$", command[offs + 1])) { | 644 | if (strchr(":^*$", command[offs + 1])) { | |
648 | char str[4]; | 645 | char str[4]; | |
649 | /* | 646 | /* | |
650 | * "!:" is shorthand for "!!:". | 647 | * "!:" is shorthand for "!!:". | |
651 | * "!^", "!*" and "!$" are shorthand for | 648 | * "!^", "!*" and "!$" are shorthand for | |
652 | * "!!:^", "!!:*" and "!!:$" respectively. | 649 | * "!!:^", "!!:*" and "!!:$" respectively. | |
653 | */ | 650 | */ | |
654 | str[0] = str[1] = '!'; | 651 | str[0] = str[1] = '!'; | |
655 | str[2] = '0'; | 652 | str[2] = '0'; | |
656 | ptr = get_history_event(str, &idx, 0); | 653 | ptr = get_history_event(str, &idx, 0); | |
657 | idx = (command[offs + 1] == ':')? 1:0; | 654 | idx = (command[offs + 1] == ':')? 1:0; | |
658 | has_mods = 1; | 655 | has_mods = 1; | |
659 | } else { | 656 | } else { | |
660 | if (command[offs + 1] == '#') { | 657 | if (command[offs + 1] == '#') { | |
661 | /* use command so far */ | 658 | /* use command so far */ | |
662 | if ((aptr = el_malloc((offs + 1) * sizeof(*aptr))) | 659 | if ((aptr = el_malloc((offs + 1) * sizeof(*aptr))) | |
663 | == NULL) | 660 | == NULL) | |
664 | return -1; | 661 | return -1; | |
665 | (void)strncpy(aptr, command, offs); | 662 | (void)strncpy(aptr, command, offs); | |
666 | aptr[offs] = '\0'; | 663 | aptr[offs] = '\0'; | |
667 | idx = 1; | 664 | idx = 1; | |
668 | } else { | 665 | } else { | |
669 | int qchar; | 666 | int qchar; | |
670 | 667 | |||
671 | qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; | 668 | qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; | |
672 | ptr = get_history_event(command + offs, &idx, qchar); | 669 | ptr = get_history_event(command + offs, &idx, qchar); | |
673 | } | 670 | } | |
674 | has_mods = command[offs + idx] == ':'; | 671 | has_mods = command[offs + idx] == ':'; | |
675 | } | 672 | } | |
676 | 673 | |||
677 | if (ptr == NULL && aptr == NULL) | 674 | if (ptr == NULL && aptr == NULL) | |
678 | return -1; | 675 | return -1; | |
679 | 676 | |||
680 | if (!has_mods) { | 677 | if (!has_mods) { | |
681 | *result = strdup(aptr ? aptr : ptr); | 678 | *result = strdup(aptr ? aptr : ptr); | |
682 | if (aptr) | 679 | if (aptr) | |
683 | el_free(aptr); | 680 | el_free(aptr); | |
684 | if (*result == NULL) | 681 | if (*result == NULL) | |
685 | return -1; | 682 | return -1; | |
686 | return 1; | 683 | return 1; | |
687 | } | 684 | } | |
688 | 685 | |||
689 | cmd = command + offs + idx + 1; | 686 | cmd = command + offs + idx + 1; | |
690 | 687 | |||
691 | /* Now parse any word designators */ | 688 | /* Now parse any word designators */ | |
692 | 689 | |||
693 | if (*cmd == '%') /* last word matched by ?pat? */ | 690 | if (*cmd == '%') /* last word matched by ?pat? */ | |
694 | tmp = strdup(last_search_match? last_search_match:""); | 691 | tmp = strdup(last_search_match? last_search_match:""); | |
695 | else if (strchr("^*$-0123456789", *cmd)) { | 692 | else if (strchr("^*$-0123456789", *cmd)) { | |
696 | start = end = -1; | 693 | start = end = -1; | |
697 | if (*cmd == '^') | 694 | if (*cmd == '^') | |
698 | start = end = 1, cmd++; | 695 | start = end = 1, cmd++; | |
699 | else if (*cmd == '$') | 696 | else if (*cmd == '$') | |
700 | start = -1, cmd++; | 697 | start = -1, cmd++; | |
701 | else if (*cmd == '*') | 698 | else if (*cmd == '*') | |
702 | start = 1, cmd++; | 699 | start = 1, cmd++; | |
703 | else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { | 700 | else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { | |
704 | start = 0; | 701 | start = 0; | |
705 | while (*cmd && '0' <= *cmd && *cmd <= '9') | 702 | while (*cmd && '0' <= *cmd && *cmd <= '9') | |
706 | start = start * 10 + *cmd++ - '0'; | 703 | start = start * 10 + *cmd++ - '0'; | |
707 | 704 | |||
708 | if (*cmd == '-') { | 705 | if (*cmd == '-') { | |
709 | if (isdigit((unsigned char) cmd[1])) { | 706 | if (isdigit((unsigned char) cmd[1])) { | |
710 | cmd++; | 707 | cmd++; | |
711 | end = 0; | 708 | end = 0; | |
712 | while (*cmd && '0' <= *cmd && *cmd <= '9') | 709 | while (*cmd && '0' <= *cmd && *cmd <= '9') | |
713 | end = end * 10 + *cmd++ - '0'; | 710 | end = end * 10 + *cmd++ - '0'; | |
714 | } else if (cmd[1] == '$') { | 711 | } else if (cmd[1] == '$') { | |
715 | cmd += 2; | 712 | cmd += 2; | |
716 | end = -1; | 713 | end = -1; | |
717 | } else { | 714 | } else { | |
718 | cmd++; | 715 | cmd++; | |
719 | end = -2; | 716 | end = -2; | |
720 | } | 717 | } | |
721 | } else if (*cmd == '*') | 718 | } else if (*cmd == '*') | |
722 | end = -1, cmd++; | 719 | end = -1, cmd++; | |
723 | else | 720 | else | |
724 | end = start; | 721 | end = start; | |
725 | } | 722 | } | |
726 | tmp = history_arg_extract(start, end, aptr? aptr:ptr); | 723 | tmp = history_arg_extract(start, end, aptr? aptr:ptr); | |
727 | if (tmp == NULL) { | 724 | if (tmp == NULL) { | |
728 | (void)fprintf(rl_outstream, "%s: Bad word specifier", | 725 | (void)fprintf(rl_outstream, "%s: Bad word specifier", | |
729 | command + offs + idx); | 726 | command + offs + idx); | |
730 | if (aptr) | 727 | if (aptr) | |
731 | el_free(aptr); | 728 | el_free(aptr); | |
732 | return -1; | 729 | return -1; | |
733 | } | 730 | } | |
734 | } else | 731 | } else | |
735 | tmp = strdup(aptr? aptr:ptr); | 732 | tmp = strdup(aptr? aptr:ptr); | |
736 | 733 | |||
737 | if (aptr) | 734 | if (aptr) | |
738 | el_free(aptr); | 735 | el_free(aptr); | |
739 | 736 | |||
740 | if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) { | 737 | if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) { | |
741 | *result = tmp; | 738 | *result = tmp; | |
742 | return 1; | 739 | return 1; | |
743 | } | 740 | } | |
744 | 741 | |||
745 | for (; *cmd; cmd++) { | 742 | for (; *cmd; cmd++) { | |
746 | if (*cmd == ':') | 743 | if (*cmd == ':') | |
747 | continue; | 744 | continue; | |
748 | else if (*cmd == 'h') { /* remove trailing path */ | 745 | else if (*cmd == 'h') { /* remove trailing path */ | |
749 | if ((aptr = strrchr(tmp, '/')) != NULL) | 746 | if ((aptr = strrchr(tmp, '/')) != NULL) | |
750 | *aptr = '\0'; | 747 | *aptr = '\0'; | |
751 | } else if (*cmd == 't') { /* remove leading path */ | 748 | } else if (*cmd == 't') { /* remove leading path */ | |
752 | if ((aptr = strrchr(tmp, '/')) != NULL) { | 749 | if ((aptr = strrchr(tmp, '/')) != NULL) { | |
753 | aptr = strdup(aptr + 1); | 750 | aptr = strdup(aptr + 1); | |
754 | el_free(tmp); | 751 | el_free(tmp); | |
755 | tmp = aptr; | 752 | tmp = aptr; | |
756 | } | 753 | } | |
757 | } else if (*cmd == 'r') { /* remove trailing suffix */ | 754 | } else if (*cmd == 'r') { /* remove trailing suffix */ | |
758 | if ((aptr = strrchr(tmp, '.')) != NULL) | 755 | if ((aptr = strrchr(tmp, '.')) != NULL) | |
759 | *aptr = '\0'; | 756 | *aptr = '\0'; | |
760 | } else if (*cmd == 'e') { /* remove all but suffix */ | 757 | } else if (*cmd == 'e') { /* remove all but suffix */ | |
761 | if ((aptr = strrchr(tmp, '.')) != NULL) { | 758 | if ((aptr = strrchr(tmp, '.')) != NULL) { | |
762 | aptr = strdup(aptr); | 759 | aptr = strdup(aptr); | |
763 | el_free(tmp); | 760 | el_free(tmp); | |
764 | tmp = aptr; | 761 | tmp = aptr; | |
765 | } | 762 | } | |
766 | } else if (*cmd == 'p') /* print only */ | 763 | } else if (*cmd == 'p') /* print only */ | |
767 | p_on = 1; | 764 | p_on = 1; | |
768 | else if (*cmd == 'g') | 765 | else if (*cmd == 'g') | |
769 | g_on = 2; | 766 | g_on = 2; | |
770 | else if (*cmd == 's' || *cmd == '&') { | 767 | else if (*cmd == 's' || *cmd == '&') { | |
771 | char *what, *with, delim; | 768 | char *what, *with, delim; | |
772 | size_t len, from_len; | 769 | size_t len, from_len; | |
773 | size_t size; | 770 | size_t size; | |
774 | 771 | |||
775 | if (*cmd == '&' && (from == NULL || to == NULL)) | 772 | if (*cmd == '&' && (from == NULL || to == NULL)) | |
776 | continue; | 773 | continue; | |
777 | else if (*cmd == 's') { | 774 | else if (*cmd == 's') { | |
778 | delim = *(++cmd), cmd++; | 775 | delim = *(++cmd), cmd++; | |
779 | size = 16; | 776 | size = 16; | |
780 | what = el_realloc(from, size * sizeof(*what)); | 777 | what = el_realloc(from, size * sizeof(*what)); | |
781 | if (what == NULL) { | 778 | if (what == NULL) { | |
782 | el_free(from); | 779 | el_free(from); | |
783 | el_free(tmp); | 780 | el_free(tmp); | |
784 | return 0; | 781 | return 0; | |
785 | } | 782 | } | |
786 | len = 0; | 783 | len = 0; | |
787 | for (; *cmd && *cmd != delim; cmd++) { | 784 | for (; *cmd && *cmd != delim; cmd++) { | |
788 | if (*cmd == '\\' && cmd[1] == delim) | 785 | if (*cmd == '\\' && cmd[1] == delim) | |
789 | cmd++; | 786 | cmd++; | |
790 | if (len >= size) { | 787 | if (len >= size) { | |
791 | char *nwhat; | 788 | char *nwhat; | |
792 | nwhat = el_realloc(what, | 789 | nwhat = el_realloc(what, | |
793 | (size <<= 1) * | 790 | (size <<= 1) * | |
794 | sizeof(*nwhat)); | 791 | sizeof(*nwhat)); | |
795 | if (nwhat == NULL) { | 792 | if (nwhat == NULL) { | |
796 | el_free(what); | 793 | el_free(what); | |
797 | el_free(tmp); | 794 | el_free(tmp); | |
798 | return 0; | 795 | return 0; | |
799 | } | 796 | } | |
800 | what = nwhat; | 797 | what = nwhat; | |
801 | } | 798 | } | |
802 | what[len++] = *cmd; | 799 | what[len++] = *cmd; | |
803 | } | 800 | } | |
804 | what[len] = '\0'; | 801 | what[len] = '\0'; | |
805 | from = what; | 802 | from = what; | |
806 | if (*what == '\0') { | 803 | if (*what == '\0') { | |
807 | el_free(what); | 804 | el_free(what); | |
808 | if (search) { | 805 | if (search) { | |
809 | from = strdup(search); | 806 | from = strdup(search); | |
810 | if (from == NULL) { | 807 | if (from == NULL) { | |
811 | el_free(tmp); | 808 | el_free(tmp); | |
812 | return 0; | 809 | return 0; | |
813 | } | 810 | } | |
814 | } else { | 811 | } else { | |
815 | from = NULL; | 812 | from = NULL; | |
816 | el_free(tmp); | 813 | el_free(tmp); | |
817 | return -1; | 814 | return -1; | |
818 | } | 815 | } | |
819 | } | 816 | } | |
820 | cmd++; /* shift after delim */ | 817 | cmd++; /* shift after delim */ | |
821 | if (!*cmd) | 818 | if (!*cmd) | |
822 | continue; | 819 | continue; | |
823 | 820 | |||
824 | size = 16; | 821 | size = 16; | |
825 | with = el_realloc(to, size * sizeof(*with)); | 822 | with = el_realloc(to, size * sizeof(*with)); | |
826 | if (with == NULL) { | 823 | if (with == NULL) { | |
827 | el_free(to); | 824 | el_free(to); | |
828 | el_free(tmp); | 825 | el_free(tmp); | |
829 | return -1; | 826 | return -1; | |
830 | } | 827 | } | |
831 | len = 0; | 828 | len = 0; | |
832 | from_len = strlen(from); | 829 | from_len = strlen(from); | |
833 | for (; *cmd && *cmd != delim; cmd++) { | 830 | for (; *cmd && *cmd != delim; cmd++) { | |
834 | if (len + from_len + 1 >= size) { | 831 | if (len + from_len + 1 >= size) { | |
835 | char *nwith; | 832 | char *nwith; | |
836 | size += from_len + 1; | 833 | size += from_len + 1; | |
837 | nwith = el_realloc(with, | 834 | nwith = el_realloc(with, | |
838 | size * sizeof(*nwith)); | 835 | size * sizeof(*nwith)); | |
839 | if (nwith == NULL) { | 836 | if (nwith == NULL) { | |
840 | el_free(with); | 837 | el_free(with); | |
841 | el_free(tmp); | 838 | el_free(tmp); | |
842 | return -1; | 839 | return -1; | |
843 | } | 840 | } | |
844 | with = nwith; | 841 | with = nwith; | |
845 | } | 842 | } | |
846 | if (*cmd == '&') { | 843 | if (*cmd == '&') { | |
847 | /* safe */ | 844 | /* safe */ | |
848 | (void)strcpy(&with[len], from); | 845 | (void)strcpy(&with[len], from); | |
849 | len += from_len; | 846 | len += from_len; | |
850 | continue; | 847 | continue; | |
851 | } | 848 | } | |
852 | if (*cmd == '\\' | 849 | if (*cmd == '\\' | |
853 | && (*(cmd + 1) == delim | 850 | && (*(cmd + 1) == delim | |
854 | || *(cmd + 1) == '&')) | 851 | || *(cmd + 1) == '&')) | |
855 | cmd++; | 852 | cmd++; | |
856 | with[len++] = *cmd; | 853 | with[len++] = *cmd; | |
857 | } | 854 | } | |
858 | with[len] = '\0'; | 855 | with[len] = '\0'; | |
859 | to = with; | 856 | to = with; | |
860 | } | 857 | } | |
861 | 858 | |||
862 | aptr = _rl_compat_sub(tmp, from, to, g_on); | 859 | aptr = _rl_compat_sub(tmp, from, to, g_on); | |
863 | if (aptr) { | 860 | if (aptr) { | |
864 | el_free(tmp); | 861 | el_free(tmp); | |
865 | tmp = aptr; | 862 | tmp = aptr; | |
866 | } | 863 | } | |
867 | g_on = 0; | 864 | g_on = 0; | |
868 | } | 865 | } | |
869 | } | 866 | } | |
870 | *result = tmp; | 867 | *result = tmp; | |
871 | return p_on? 2:1; | 868 | return p_on? 2:1; | |
872 | } | 869 | } | |
873 | 870 | |||
874 | 871 | |||
875 | /* | 872 | /* | |
876 | * csh-style history expansion | 873 | * csh-style history expansion | |
877 | */ | 874 | */ | |
878 | int | 875 | int | |
879 | history_expand(char *str, char **output) | 876 | history_expand(char *str, char **output) | |
880 | { | 877 | { | |
881 | int ret = 0; | 878 | int ret = 0; | |
882 | size_t idx, i, size; | 879 | size_t idx, i, size; | |
883 | char *tmp, *result; | 880 | char *tmp, *result; | |
884 | 881 | |||
885 | if (h == NULL || e == NULL) | 882 | if (h == NULL || e == NULL) | |
886 | rl_initialize(); | 883 | rl_initialize(); | |
887 | 884 | |||
888 | if (history_expansion_char == 0) { | 885 | if (history_expansion_char == 0) { | |
889 | *output = strdup(str); | 886 | *output = strdup(str); | |
890 | return 0; | 887 | return 0; | |
891 | } | 888 | } | |
892 | 889 | |||
893 | *output = NULL; | 890 | *output = NULL; | |
894 | if (str[0] == history_subst_char) { | 891 | if (str[0] == history_subst_char) { | |
895 | /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ | 892 | /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ | |
896 | *output = el_malloc((strlen(str) + 4 + 1) * sizeof(*output)); | 893 | *output = el_malloc((strlen(str) + 4 + 1) * sizeof(*output)); | |
897 | if (*output == NULL) | 894 | if (*output == NULL) | |
898 | return 0; | 895 | return 0; | |
899 | (*output)[0] = (*output)[1] = history_expansion_char; | 896 | (*output)[0] = (*output)[1] = history_expansion_char; | |
900 | (*output)[2] = ':'; | 897 | (*output)[2] = ':'; | |
901 | (*output)[3] = 's'; | 898 | (*output)[3] = 's'; | |
902 | (void)strcpy((*output) + 4, str); | 899 | (void)strcpy((*output) + 4, str); | |
903 | str = *output; | 900 | str = *output; | |
904 | } else { | 901 | } else { | |
905 | *output = strdup(str); | 902 | *output = strdup(str); | |
906 | if (*output == NULL) | 903 | if (*output == NULL) | |
907 | return 0; | 904 | return 0; | |
908 | } | 905 | } | |
909 | 906 | |||
910 | #define ADD_STRING(what, len, fr) \ | 907 | #define ADD_STRING(what, len, fr) \ | |
911 | { \ | 908 | { \ | |
912 | if (idx + len + 1 > size) { \ | 909 | if (idx + len + 1 > size) { \ | |
913 | char *nresult = el_realloc(result, \ | 910 | char *nresult = el_realloc(result, \ | |
914 | (size += len + 1) * sizeof(*nresult)); \ | 911 | (size += len + 1) * sizeof(*nresult)); \ | |
915 | if (nresult == NULL) { \ | 912 | if (nresult == NULL) { \ | |
916 | el_free(*output); \ | 913 | el_free(*output); \ | |
917 | if (/*CONSTCOND*/fr) \ | 914 | if (/*CONSTCOND*/fr) \ | |
918 | el_free(tmp); \ | 915 | el_free(tmp); \ | |
919 | return 0; \ | 916 | return 0; \ | |
920 | } \ | 917 | } \ | |
921 | result = nresult; \ | 918 | result = nresult; \ | |
922 | } \ | 919 | } \ | |
923 | (void)strncpy(&result[idx], what, len); \ | 920 | (void)strncpy(&result[idx], what, len); \ | |
924 | idx += len; \ | 921 | idx += len; \ | |
925 | result[idx] = '\0'; \ | 922 | result[idx] = '\0'; \ | |
926 | } | 923 | } | |
927 | 924 | |||
928 | result = NULL; | 925 | result = NULL; | |
929 | size = idx = 0; | 926 | size = idx = 0; | |
930 | tmp = NULL; | 927 | tmp = NULL; | |
931 | for (i = 0; str[i];) { | 928 | for (i = 0; str[i];) { | |
932 | int qchar, loop_again; | 929 | int qchar, loop_again; | |
933 | size_t len, start, j; | 930 | size_t len, start, j; | |
934 | 931 | |||
935 | qchar = 0; | 932 | qchar = 0; | |
936 | loop_again = 1; | 933 | loop_again = 1; | |
937 | start = j = i; | 934 | start = j = i; | |
938 | loop: | 935 | loop: | |
939 | for (; str[j]; j++) { | 936 | for (; str[j]; j++) { | |
940 | if (str[j] == '\\' && | 937 | if (str[j] == '\\' && | |
941 | str[j + 1] == history_expansion_char) { | 938 | str[j + 1] == history_expansion_char) { | |
942 | (void)strcpy(&str[j], &str[j + 1]); | 939 | (void)strcpy(&str[j], &str[j + 1]); | |
943 | continue; | 940 | continue; | |
944 | } | 941 | } | |
945 | if (!loop_again) { | 942 | if (!loop_again) { | |
946 | if (isspace((unsigned char) str[j]) | 943 | if (isspace((unsigned char) str[j]) | |
947 | || str[j] == qchar) | 944 | || str[j] == qchar) | |
948 | break; | 945 | break; | |
949 | } | 946 | } | |
950 | if (str[j] == history_expansion_char | 947 | if (str[j] == history_expansion_char | |
951 | && !strchr(history_no_expand_chars, str[j + 1]) | 948 | && !strchr(history_no_expand_chars, str[j + 1]) | |
952 | && (!history_inhibit_expansion_function || | 949 | && (!history_inhibit_expansion_function || | |
953 | (*history_inhibit_expansion_function)(str, | 950 | (*history_inhibit_expansion_function)(str, | |
954 | (int)j) == 0)) | 951 | (int)j) == 0)) | |
955 | break; | 952 | break; | |
956 | } | 953 | } | |
957 | 954 | |||
958 | if (str[j] && loop_again) { | 955 | if (str[j] && loop_again) { | |
959 | i = j; | 956 | i = j; | |
960 | qchar = (j > 0 && str[j - 1] == '"' )? '"':0; | 957 | qchar = (j > 0 && str[j - 1] == '"' )? '"':0; | |
961 | j++; | 958 | j++; | |
962 | if (str[j] == history_expansion_char) | 959 | if (str[j] == history_expansion_char) | |
963 | j++; | 960 | j++; | |
964 | loop_again = 0; | 961 | loop_again = 0; | |
965 | goto loop; | 962 | goto loop; | |
966 | } | 963 | } | |
967 | len = i - start; | 964 | len = i - start; | |
968 | ADD_STRING(&str[start], len, 0); | 965 | ADD_STRING(&str[start], len, 0); | |
969 | 966 | |||
970 | if (str[i] == '\0' || str[i] != history_expansion_char) { | 967 | if (str[i] == '\0' || str[i] != history_expansion_char) { | |
971 | len = j - i; | 968 | len = j - i; | |
972 | ADD_STRING(&str[i], len, 0); | 969 | ADD_STRING(&str[i], len, 0); | |
973 | if (start == 0) | 970 | if (start == 0) | |
974 | ret = 0; | 971 | ret = 0; | |
975 | else | 972 | else | |
976 | ret = 1; | 973 | ret = 1; | |
977 | break; | 974 | break; | |
978 | } | 975 | } | |
979 | ret = _history_expand_command (str, i, (j - i), &tmp); | 976 | ret = _history_expand_command (str, i, (j - i), &tmp); | |
980 | if (ret > 0 && tmp) { | 977 | if (ret > 0 && tmp) { | |
981 | len = strlen(tmp); | 978 | len = strlen(tmp); | |
982 | ADD_STRING(tmp, len, 1); | 979 | ADD_STRING(tmp, len, 1); | |
983 | } | 980 | } | |
984 | if (tmp) { | 981 | if (tmp) { | |
985 | el_free(tmp); | 982 | el_free(tmp); | |
986 | tmp = NULL; | 983 | tmp = NULL; | |
987 | } | 984 | } | |
988 | i = j; | 985 | i = j; | |
989 | } | 986 | } | |
990 | 987 | |||
991 | /* ret is 2 for "print only" option */ | 988 | /* ret is 2 for "print only" option */ | |
992 | if (ret == 2) { | 989 | if (ret == 2) { | |
993 | add_history(result); | 990 | add_history(result); | |
994 | #ifdef GDB_411_HACK | 991 | #ifdef GDB_411_HACK | |
995 | /* gdb 4.11 has been shipped with readline, where */ | 992 | /* gdb 4.11 has been shipped with readline, where */ | |
996 | /* history_expand() returned -1 when the line */ | 993 | /* history_expand() returned -1 when the line */ | |
997 | /* should not be executed; in readline 2.1+ */ | 994 | /* should not be executed; in readline 2.1+ */ | |
998 | /* it should return 2 in such a case */ | 995 | /* it should return 2 in such a case */ | |
999 | ret = -1; | 996 | ret = -1; | |
1000 | #endif | 997 | #endif | |
1001 | } | 998 | } | |
1002 | el_free(*output); | 999 | el_free(*output); | |
1003 | *output = result; | 1000 | *output = result; | |
1004 | 1001 | |||
1005 | return ret; | 1002 | return ret; | |
1006 | } | 1003 | } | |
1007 | 1004 | |||
1008 | /* | 1005 | /* | |
1009 | * Return a string consisting of arguments of "str" from "start" to "end". | 1006 | * Return a string consisting of arguments of "str" from "start" to "end". | |
1010 | */ | 1007 | */ | |
1011 | char * | 1008 | char * | |
1012 | history_arg_extract(int start, int end, const char *str) | 1009 | history_arg_extract(int start, int end, const char *str) | |
1013 | { | 1010 | { | |
1014 | size_t i, len, max; | 1011 | size_t i, len, max; | |
1015 | char **arr, *result = NULL; | 1012 | char **arr, *result = NULL; | |
1016 | 1013 | |||
1017 | arr = history_tokenize(str); | 1014 | arr = history_tokenize(str); | |
1018 | if (!arr) | 1015 | if (!arr) | |
1019 | return NULL; | 1016 | return NULL; | |
1020 | if (arr && *arr == NULL) | 1017 | if (arr && *arr == NULL) | |
1021 | goto out; | 1018 | goto out; | |
1022 | 1019 | |||
1023 | for (max = 0; arr[max]; max++) | 1020 | for (max = 0; arr[max]; max++) | |
1024 | continue; | 1021 | continue; | |
1025 | max--; | 1022 | max--; | |
1026 | 1023 | |||
1027 | if (start == '$') | 1024 | if (start == '$') | |
1028 | start = (int)max; | 1025 | start = (int)max; | |
1029 | if (end == '$') | 1026 | if (end == '$') | |
1030 | end = (int)max; | 1027 | end = (int)max; | |
1031 | if (end < 0) | 1028 | if (end < 0) | |
1032 | end = (int)max + end + 1; | 1029 | end = (int)max + end + 1; | |
1033 | if (start < 0) | 1030 | if (start < 0) | |
1034 | start = end; | 1031 | start = end; | |
1035 | 1032 | |||
1036 | if (start < 0 || end < 0 || (size_t)start > max || | 1033 | if (start < 0 || end < 0 || (size_t)start > max || | |
1037 | (size_t)end > max || start > end) | 1034 | (size_t)end > max || start > end) | |
1038 | goto out; | 1035 | goto out; | |
1039 | 1036 | |||
1040 | for (i = start, len = 0; i <= (size_t)end; i++) | 1037 | for (i = start, len = 0; i <= (size_t)end; i++) | |
1041 | len += strlen(arr[i]) + 1; | 1038 | len += strlen(arr[i]) + 1; | |
1042 | len++; | 1039 | len++; | |
1043 | result = el_malloc(len * sizeof(*result)); | 1040 | result = el_malloc(len * sizeof(*result)); | |
1044 | if (result == NULL) | 1041 | if (result == NULL) | |
1045 | goto out; | 1042 | goto out; | |
1046 | 1043 | |||
1047 | for (i = start, len = 0; i <= (size_t)end; i++) { | 1044 | for (i = start, len = 0; i <= (size_t)end; i++) { | |
1048 | (void)strcpy(result + len, arr[i]); | 1045 | (void)strcpy(result + len, arr[i]); | |
1049 | len += strlen(arr[i]); | 1046 | len += strlen(arr[i]); | |
1050 | if (i < (size_t)end) | 1047 | if (i < (size_t)end) | |
1051 | result[len++] = ' '; | 1048 | result[len++] = ' '; | |
1052 | } | 1049 | } | |
1053 | result[len] = '\0'; | 1050 | result[len] = '\0'; | |
1054 | 1051 | |||
1055 | out: | 1052 | out: | |
1056 | for (i = 0; arr[i]; i++) | 1053 | for (i = 0; arr[i]; i++) | |
1057 | el_free(arr[i]); | 1054 | el_free(arr[i]); | |
1058 | el_free(arr); | 1055 | el_free(arr); | |
1059 | 1056 | |||
1060 | return result; | 1057 | return result; | |
1061 | } | 1058 | } | |
1062 | 1059 | |||
1063 | /* | 1060 | /* | |
1064 | * Parse the string into individual tokens, | 1061 | * Parse the string into individual tokens, | |
1065 | * similar to how shell would do it. | 1062 | * similar to how shell would do it. | |
1066 | */ | 1063 | */ | |
1067 | char ** | 1064 | char ** | |
1068 | history_tokenize(const char *str) | 1065 | history_tokenize(const char *str) | |
1069 | { | 1066 | { | |
1070 | int size = 1, idx = 0, i, start; | 1067 | int size = 1, idx = 0, i, start; | |
1071 | size_t len; | 1068 | size_t len; | |
1072 | char **result = NULL, *temp, delim = '\0'; | 1069 | char **result = NULL, *temp, delim = '\0'; | |
1073 | 1070 | |||
1074 | for (i = 0; str[i];) { | 1071 | for (i = 0; str[i];) { | |
1075 | while (isspace((unsigned char) str[i])) | 1072 | while (isspace((unsigned char) str[i])) | |
1076 | i++; | 1073 | i++; | |
1077 | start = i; | 1074 | start = i; | |
1078 | for (; str[i];) { | 1075 | for (; str[i];) { | |
1079 | if (str[i] == '\\') { | 1076 | if (str[i] == '\\') { | |
1080 | if (str[i+1] != '\0') | 1077 | if (str[i+1] != '\0') | |
1081 | i++; | 1078 | i++; | |
1082 | } else if (str[i] == delim) | 1079 | } else if (str[i] == delim) | |
1083 | delim = '\0'; | 1080 | delim = '\0'; | |
1084 | else if (!delim && | 1081 | else if (!delim && | |
1085 | (isspace((unsigned char) str[i]) || | 1082 | (isspace((unsigned char) str[i]) || | |
1086 | strchr("()<>;&|$", str[i]))) | 1083 | strchr("()<>;&|$", str[i]))) | |
1087 | break; | 1084 | break; | |
1088 | else if (!delim && strchr("'`\"", str[i])) | 1085 | else if (!delim && strchr("'`\"", str[i])) | |
1089 | delim = str[i]; | 1086 | delim = str[i]; | |
1090 | if (str[i]) | 1087 | if (str[i]) | |
1091 | i++; | 1088 | i++; | |
1092 | } | 1089 | } | |
1093 | 1090 | |||
1094 | if (idx + 2 >= size) { | 1091 | if (idx + 2 >= size) { | |
1095 | char **nresult; | 1092 | char **nresult; | |
1096 | size <<= 1; | 1093 | size <<= 1; | |
1097 | nresult = el_realloc(result, size * sizeof(*nresult)); | 1094 | nresult = el_realloc(result, size * sizeof(*nresult)); | |
1098 | if (nresult == NULL) { | 1095 | if (nresult == NULL) { | |
1099 | el_free(result); | 1096 | el_free(result); | |
1100 | return NULL; | 1097 | return NULL; | |
1101 | } | 1098 | } | |
1102 | result = nresult; | 1099 | result = nresult; | |
1103 | } | 1100 | } | |
1104 | len = i - start; | 1101 | len = i - start; | |
1105 | temp = el_malloc((len + 1) * sizeof(*temp)); | 1102 | temp = el_malloc((len + 1) * sizeof(*temp)); | |
1106 | if (temp == NULL) { | 1103 | if (temp == NULL) { | |
1107 | for (i = 0; i < idx; i++) | 1104 | for (i = 0; i < idx; i++) | |
1108 | el_free(result[i]); | 1105 | el_free(result[i]); | |
1109 | el_free(result); | 1106 | el_free(result); | |
1110 | return NULL; | 1107 | return NULL; | |
1111 | } | 1108 | } | |
1112 | (void)strncpy(temp, &str[start], len); | 1109 | (void)strncpy(temp, &str[start], len); | |
1113 | temp[len] = '\0'; | 1110 | temp[len] = '\0'; | |
1114 | result[idx++] = temp; | 1111 | result[idx++] = temp; | |
1115 | result[idx] = NULL; | 1112 | result[idx] = NULL; | |
1116 | if (str[i]) | 1113 | if (str[i]) | |
1117 | i++; | 1114 | i++; | |
1118 | } | 1115 | } | |
1119 | return result; | 1116 | return result; | |
1120 | } | 1117 | } | |
1121 | 1118 | |||
1122 | 1119 | |||
1123 | /* | 1120 | /* | |
1124 | * limit size of history record to ``max'' events | 1121 | * limit size of history record to ``max'' events | |
1125 | */ | 1122 | */ | |
1126 | void | 1123 | void | |
1127 | stifle_history(int max) | 1124 | stifle_history(int max) | |
1128 | { | 1125 | { | |
1129 | HistEvent ev; | 1126 | HistEvent ev; | |
1130 | 1127 | |||
1131 | if (h == NULL || e == NULL) | 1128 | if (h == NULL || e == NULL) | |
1132 | rl_initialize(); | 1129 | rl_initialize(); | |
1133 | 1130 | |||
1134 | if (history(h, &ev, H_SETSIZE, max) == 0) | 1131 | if (history(h, &ev, H_SETSIZE, max) == 0) | |
1135 | max_input_history = max; | 1132 | max_input_history = max; | |
1136 | } | 1133 | } | |
1137 | 1134 | |||
1138 | 1135 | |||
1139 | /* | 1136 | /* | |
1140 | * "unlimit" size of history - set the limit to maximum allowed int value | 1137 | * "unlimit" size of history - set the limit to maximum allowed int value | |
1141 | */ | 1138 | */ | |
1142 | int | 1139 | int | |
1143 | unstifle_history(void) | 1140 | unstifle_history(void) | |
1144 | { | 1141 | { | |
1145 | HistEvent ev; | 1142 | HistEvent ev; | |
1146 | int omax; | 1143 | int omax; | |
1147 | 1144 | |||
1148 | history(h, &ev, H_SETSIZE, INT_MAX); | 1145 | history(h, &ev, H_SETSIZE, INT_MAX); | |
1149 | omax = max_input_history; | 1146 | omax = max_input_history; | |
1150 | max_input_history = INT_MAX; | 1147 | max_input_history = INT_MAX; | |
1151 | return omax; /* some value _must_ be returned */ | 1148 | return omax; /* some value _must_ be returned */ | |
1152 | } | 1149 | } | |
1153 | 1150 | |||
1154 | 1151 | |||
1155 | int | 1152 | int | |
1156 | history_is_stifled(void) | 1153 | history_is_stifled(void) | |
1157 | { | 1154 | { | |
1158 | 1155 | |||
1159 | /* cannot return true answer */ | 1156 | /* cannot return true answer */ | |
1160 | return max_input_history != INT_MAX; | 1157 | return max_input_history != INT_MAX; | |
1161 | } | 1158 | } | |
1162 | 1159 | |||
1163 | static const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; | 1160 | static const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; | |
1164 | 1161 | |||
1165 | int | 1162 | int | |
1166 | history_truncate_file (const char *filename, int nlines) | 1163 | history_truncate_file (const char *filename, int nlines) | |
1167 | { | 1164 | { | |
1168 | int ret = 0; | 1165 | int ret = 0; | |
1169 | FILE *fp, *tp; | 1166 | FILE *fp, *tp; | |
1170 | char template[sizeof(_history_tmp_template)]; | 1167 | char template[sizeof(_history_tmp_template)]; | |
1171 | char buf[4096]; | 1168 | char buf[4096]; | |
1172 | int fd; | 1169 | int fd; | |
1173 | char *cp; | 1170 | char *cp; | |
1174 | off_t off; | 1171 | off_t off; | |
1175 | int count = 0; | 1172 | int count = 0; | |
1176 | ssize_t left = 0; | 1173 | ssize_t left = 0; | |
1177 | 1174 | |||
1178 | if (filename == NULL && (filename = _default_history_file()) == NULL) | 1175 | if (filename == NULL && (filename = _default_history_file()) == NULL) | |
1179 | return errno; | 1176 | return errno; | |
1180 | if ((fp = fopen(filename, "r+")) == NULL) | 1177 | if ((fp = fopen(filename, "r+")) == NULL) | |
1181 | return errno; | 1178 | return errno; | |
1182 | strcpy(template, _history_tmp_template); | 1179 | strcpy(template, _history_tmp_template); | |
1183 | if ((fd = mkstemp(template)) == -1) { | 1180 | if ((fd = mkstemp(template)) == -1) { | |
1184 | ret = errno; | 1181 | ret = errno; | |
1185 | goto out1; | 1182 | goto out1; | |
1186 | } | 1183 | } | |
1187 | 1184 | |||
1188 | if ((tp = fdopen(fd, "r+")) == NULL) { | 1185 | if ((tp = fdopen(fd, "r+")) == NULL) { | |
1189 | close(fd); | 1186 | close(fd); | |
1190 | ret = errno; | 1187 | ret = errno; | |
1191 | goto out2; | 1188 | goto out2; | |
1192 | } | 1189 | } | |
1193 | 1190 | |||
1194 | for(;;) { | 1191 | for(;;) { | |
1195 | if (fread(buf, sizeof(buf), 1, fp) != 1) { | 1192 | if (fread(buf, sizeof(buf), 1, fp) != 1) { | |
1196 | if (ferror(fp)) { | 1193 | if (ferror(fp)) { | |
1197 | ret = errno; | 1194 | ret = errno; | |
1198 | break; | 1195 | break; | |
1199 | } | 1196 | } | |
1200 | if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == | 1197 | if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == | |
1201 | (off_t)-1) { | 1198 | (off_t)-1) { | |
1202 | ret = errno; | 1199 | ret = errno; | |
1203 | break; | 1200 | break; | |
1204 | } | 1201 | } | |
1205 | left = fread(buf, 1, sizeof(buf), fp); | 1202 | left = fread(buf, 1, sizeof(buf), fp); | |
1206 | if (ferror(fp)) { | 1203 | if (ferror(fp)) { | |
1207 | ret = errno; | 1204 | ret = errno; | |
1208 | break; | 1205 | break; | |
1209 | } | 1206 | } | |
1210 | if (left == 0) { | 1207 | if (left == 0) { | |
1211 | count--; | 1208 | count--; | |
1212 | left = sizeof(buf); | 1209 | left = sizeof(buf); | |
1213 | } else if (fwrite(buf, (size_t)left, 1, tp) != 1) { | 1210 | } else if (fwrite(buf, (size_t)left, 1, tp) != 1) { | |
1214 | ret = errno; | 1211 | ret = errno; | |
1215 | break; | 1212 | break; | |
1216 | } | 1213 | } | |
1217 | fflush(tp); | 1214 | fflush(tp); | |
1218 | break; | 1215 | break; | |
1219 | } | 1216 | } | |
1220 | if (fwrite(buf, sizeof(buf), 1, tp) != 1) { | 1217 | if (fwrite(buf, sizeof(buf), 1, tp) != 1) { | |
1221 | ret = errno; | 1218 | ret = errno; | |
1222 | break; | 1219 | break; | |
1223 | } | 1220 | } | |
1224 | count++; | 1221 | count++; | |
1225 | } | 1222 | } | |
1226 | if (ret) | 1223 | if (ret) | |
1227 | goto out3; | 1224 | goto out3; | |
1228 | cp = buf + left - 1; | 1225 | cp = buf + left - 1; | |
1229 | if(*cp != '\n') | 1226 | if(*cp != '\n') | |
1230 | cp++; | 1227 | cp++; | |
1231 | for(;;) { | 1228 | for(;;) { | |
1232 | while (--cp >= buf) { | 1229 | while (--cp >= buf) { | |
1233 | if (*cp == '\n') { | 1230 | if (*cp == '\n') { | |
1234 | if (--nlines == 0) { | 1231 | if (--nlines == 0) { | |
1235 | if (++cp >= buf + sizeof(buf)) { | 1232 | if (++cp >= buf + sizeof(buf)) { | |
1236 | count++; | 1233 | count++; | |
1237 | cp = buf; | 1234 | cp = buf; | |
1238 | } | 1235 | } | |
1239 | break; | 1236 | break; | |
1240 | } | 1237 | } | |
1241 | } | 1238 | } | |
1242 | } | 1239 | } | |
1243 | if (nlines <= 0 || count == 0) | 1240 | if (nlines <= 0 || count == 0) | |
1244 | break; | 1241 | break; | |
1245 | count--; | 1242 | count--; | |
1246 | if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { | 1243 | if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { | |
1247 | ret = errno; | 1244 | ret = errno; | |
1248 | break; | 1245 | break; | |
1249 | } | 1246 | } | |
1250 | if (fread(buf, sizeof(buf), 1, tp) != 1) { | 1247 | if (fread(buf, sizeof(buf), 1, tp) != 1) { | |
1251 | if (ferror(tp)) { | 1248 | if (ferror(tp)) { | |
1252 | ret = errno; | 1249 | ret = errno; | |
1253 | break; | 1250 | break; | |
1254 | } | 1251 | } | |
1255 | ret = EAGAIN; | 1252 | ret = EAGAIN; | |
1256 | break; | 1253 | break; | |
1257 | } | 1254 | } | |
1258 | cp = buf + sizeof(buf); | 1255 | cp = buf + sizeof(buf); | |
1259 | } | 1256 | } | |
1260 | 1257 | |||
1261 | if (ret || nlines > 0) | 1258 | if (ret || nlines > 0) | |
1262 | goto out3; | 1259 | goto out3; | |
1263 | 1260 | |||
1264 | if (fseeko(fp, 0, SEEK_SET) == (off_t)-1) { | 1261 | if (fseeko(fp, 0, SEEK_SET) == (off_t)-1) { | |
1265 | ret = errno; | 1262 | ret = errno; | |
1266 | goto out3; | 1263 | goto out3; | |
1267 | } | 1264 | } | |
1268 | 1265 | |||
1269 | if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == | 1266 | if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == | |
1270 | (off_t)-1) { | 1267 | (off_t)-1) { | |
1271 | ret = errno; | 1268 | ret = errno; | |
1272 | goto out3; | 1269 | goto out3; | |
1273 | } | 1270 | } | |
1274 | 1271 | |||
1275 | for(;;) { | 1272 | for(;;) { | |
1276 | if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) { | 1273 | if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) { | |
1277 | if (ferror(fp)) | 1274 | if (ferror(fp)) | |
1278 | ret = errno; | 1275 | ret = errno; | |
1279 | break; | 1276 | break; | |
1280 | } | 1277 | } | |
1281 | if (fwrite(buf, (size_t)left, 1, fp) != 1) { | 1278 | if (fwrite(buf, (size_t)left, 1, fp) != 1) { | |
1282 | ret = errno; | 1279 | ret = errno; | |
1283 | break; | 1280 | break; | |
1284 | } | 1281 | } | |
1285 | } | 1282 | } | |
1286 | fflush(fp); | 1283 | fflush(fp); | |
1287 | if((off = ftello(fp)) > 0) | 1284 | if((off = ftello(fp)) > 0) | |
1288 | (void)ftruncate(fileno(fp), off); | 1285 | (void)ftruncate(fileno(fp), off); | |
1289 | out3: | 1286 | out3: | |
1290 | fclose(tp); | 1287 | fclose(tp); | |
1291 | out2: | 1288 | out2: | |
1292 | unlink(template); | 1289 | unlink(template); | |
1293 | out1: | 1290 | out1: | |
1294 | fclose(fp); | 1291 | fclose(fp); | |
1295 | 1292 | |||
1296 | return ret; | 1293 | return ret; | |
1297 | } | 1294 | } | |
1298 | 1295 | |||
1299 | 1296 | |||
1300 | /* | 1297 | /* | |
1301 | * read history from a file given | 1298 | * read history from a file given | |
1302 | */ | 1299 | */ | |
1303 | int | 1300 | int | |
1304 | read_history(const char *filename) | 1301 | read_history(const char *filename) | |
1305 | { | 1302 | { | |
1306 | HistEvent ev; | 1303 | HistEvent ev; | |
1307 | 1304 | |||
1308 | if (h == NULL || e == NULL) | 1305 | if (h == NULL || e == NULL) | |
1309 | rl_initialize(); | 1306 | rl_initialize(); | |
1310 | if (filename == NULL && (filename = _default_history_file()) == NULL) | 1307 | if (filename == NULL && (filename = _default_history_file()) == NULL) | |
1311 | return errno; | 1308 | return errno; | |
1312 | return history(h, &ev, H_LOAD, filename) == -1 ? | 1309 | return history(h, &ev, H_LOAD, filename) == -1 ? | |
1313 | (errno ? errno : EINVAL) : 0; | 1310 | (errno ? errno : EINVAL) : 0; | |
1314 | } | 1311 | } | |
1315 | 1312 | |||
1316 | 1313 | |||
1317 | /* | 1314 | /* | |
1318 | * write history to a file given | 1315 | * write history to a file given | |
1319 | */ | 1316 | */ | |
1320 | int | 1317 | int | |
1321 | write_history(const char *filename) | 1318 | write_history(const char *filename) | |
1322 | { | 1319 | { | |
1323 | HistEvent ev; | 1320 | HistEvent ev; | |
1324 | 1321 | |||
1325 | if (h == NULL || e == NULL) | 1322 | if (h == NULL || e == NULL) | |
1326 | rl_initialize(); | 1323 | rl_initialize(); | |
1327 | if (filename == NULL && (filename = _default_history_file()) == NULL) | 1324 | if (filename == NULL && (filename = _default_history_file()) == NULL) | |
1328 | return errno; | 1325 | return errno; | |
1329 | return history(h, &ev, H_SAVE, filename) == -1 ? | 1326 | return history(h, &ev, H_SAVE, filename) == -1 ? | |
1330 | (errno ? errno : EINVAL) : 0; | 1327 | (errno ? errno : EINVAL) : 0; | |
1331 | } | 1328 | } | |
1332 | 1329 | |||
1333 | 1330 | |||
1334 | /* | 1331 | /* | |
1335 | * returns history ``num''th event | 1332 | * returns history ``num''th event | |
1336 | * | 1333 | * | |
1337 | * returned pointer points to static variable | 1334 | * returned pointer points to static variable | |
1338 | */ | 1335 | */ | |
1339 | HIST_ENTRY * | 1336 | HIST_ENTRY * | |
1340 | history_get(int num) | 1337 | history_get(int num) | |
1341 | { | 1338 | { | |
1342 | static HIST_ENTRY she; | 1339 | static HIST_ENTRY she; | |
1343 | HistEvent ev; | 1340 | HistEvent ev; | |
1344 | int curr_num; | 1341 | int curr_num; | |
1345 | 1342 | |||
1346 | if (h == NULL || e == NULL) | 1343 | if (h == NULL || e == NULL) | |
1347 | rl_initialize(); | 1344 | rl_initialize(); | |
1348 | 1345 | |||
1349 | /* save current position */ | 1346 | /* save current position */ | |
1350 | if (history(h, &ev, H_CURR) != 0) | 1347 | if (history(h, &ev, H_CURR) != 0) | |
1351 | return NULL; | 1348 | return NULL; | |
1352 | curr_num = ev.num; | 1349 | curr_num = ev.num; | |
1353 | 1350 | |||
1354 | /* start from the oldest */ | 1351 | /* start from the oldest */ | |
1355 | if (history(h, &ev, H_LAST) != 0) | 1352 | if (history(h, &ev, H_LAST) != 0) | |
1356 | return NULL; /* error */ | 1353 | return NULL; /* error */ | |
1357 | 1354 | |||
1358 | /* look forwards for event matching specified offset */ | 1355 | /* look forwards for event matching specified offset */ | |
1359 | if (history(h, &ev, H_NEXT_EVDATA, num, &she.data)) | 1356 | if (history(h, &ev, H_NEXT_EVDATA, num, &she.data)) | |
1360 | return NULL; | 1357 | return NULL; | |
1361 | 1358 | |||
1362 | she.line = ev.str; | 1359 | she.line = ev.str; | |
1363 | 1360 | |||
1364 | /* restore pointer to where it was */ | 1361 | /* restore pointer to where it was */ | |
1365 | (void)history(h, &ev, H_SET, curr_num); | 1362 | (void)history(h, &ev, H_SET, curr_num); | |
1366 | 1363 | |||
1367 | return &she; | 1364 | return &she; | |
1368 | } | 1365 | } | |
1369 | 1366 | |||
1370 | 1367 | |||
1371 | /* | 1368 | /* | |
1372 | * add the line to history table | 1369 | * add the line to history table | |
1373 | */ | 1370 | */ | |
1374 | int | 1371 | int | |
1375 | add_history(const char *line) | 1372 | add_history(const char *line) | |
1376 | { | 1373 | { | |
1377 | HistEvent ev; | 1374 | HistEvent ev; | |
1378 | 1375 | |||
1379 | if (h == NULL || e == NULL) | 1376 | if (h == NULL || e == NULL) | |
1380 | rl_initialize(); | 1377 | rl_initialize(); | |
1381 | 1378 | |||
1382 | (void)history(h, &ev, H_ENTER, line); | 1379 | (void)history(h, &ev, H_ENTER, line); | |
1383 | if (history(h, &ev, H_GETSIZE) == 0) | 1380 | if (history(h, &ev, H_GETSIZE) == 0) | |
1384 | history_length = ev.num; | 1381 | history_length = ev.num; | |
1385 | 1382 | |||
1386 | return !(history_length > 0); /* return 0 if all is okay */ | 1383 | return !(history_length > 0); /* return 0 if all is okay */ | |
1387 | } | 1384 | } | |
1388 | 1385 | |||
1389 | 1386 | |||
1390 | /* | 1387 | /* | |
1391 | * remove the specified entry from the history list and return it. | 1388 | * remove the specified entry from the history list and return it. | |
1392 | */ | 1389 | */ | |
1393 | HIST_ENTRY * | 1390 | HIST_ENTRY * | |
1394 | remove_history(int num) | 1391 | remove_history(int num) | |
1395 | { | 1392 | { | |
1396 | HIST_ENTRY *he; | 1393 | HIST_ENTRY *he; | |
1397 | HistEvent ev; | 1394 | HistEvent ev; | |
1398 | 1395 | |||
1399 | if (h == NULL || e == NULL) | 1396 | if (h == NULL || e == NULL) | |
1400 | rl_initialize(); | 1397 | rl_initialize(); | |
1401 | 1398 | |||
1402 | if ((he = el_malloc(sizeof(*he))) == NULL) | 1399 | if ((he = el_malloc(sizeof(*he))) == NULL) | |
1403 | return NULL; | 1400 | return NULL; | |
1404 | 1401 | |||
1405 | if (history(h, &ev, H_DELDATA, num, &he->data) != 0) { | 1402 | if (history(h, &ev, H_DELDATA, num, &he->data) != 0) { | |
1406 | el_free(he); | 1403 | el_free(he); | |
1407 | return NULL; | 1404 | return NULL; | |
1408 | } | 1405 | } | |
1409 | 1406 | |||
1410 | he->line = ev.str; | 1407 | he->line = ev.str; | |
1411 | if (history(h, &ev, H_GETSIZE) == 0) | 1408 | if (history(h, &ev, H_GETSIZE) == 0) | |
1412 | history_length = ev.num; | 1409 | history_length = ev.num; | |
1413 | 1410 | |||
1414 | return he; | 1411 | return he; | |
1415 | } | 1412 | } | |
1416 | 1413 | |||
1417 | 1414 | |||
1418 | /* | 1415 | /* | |
1419 | * replace the line and data of the num-th entry | 1416 | * replace the line and data of the num-th entry | |
1420 | */ | 1417 | */ | |
1421 | HIST_ENTRY * | 1418 | HIST_ENTRY * | |
1422 | replace_history_entry(int num, const char *line, histdata_t data) | 1419 | replace_history_entry(int num, const char *line, histdata_t data) | |
1423 | { | 1420 | { | |
1424 | HIST_ENTRY *he; | 1421 | HIST_ENTRY *he; | |
1425 | HistEvent ev; | 1422 | HistEvent ev; | |
1426 | int curr_num; | 1423 | int curr_num; | |
1427 | 1424 | |||
1428 | if (h == NULL || e == NULL) | 1425 | if (h == NULL || e == NULL) | |
1429 | rl_initialize(); | 1426 | rl_initialize(); | |
1430 | 1427 | |||
1431 | /* save current position */ | 1428 | /* save current position */ | |
1432 | if (history(h, &ev, H_CURR) != 0) | 1429 | if (history(h, &ev, H_CURR) != 0) | |
1433 | return NULL; | 1430 | return NULL; | |
1434 | curr_num = ev.num; | 1431 | curr_num = ev.num; | |
1435 | 1432 | |||
1436 | /* start from the oldest */ | 1433 | /* start from the oldest */ | |
1437 | if (history(h, &ev, H_LAST) != 0) | 1434 | if (history(h, &ev, H_LAST) != 0) | |
1438 | return NULL; /* error */ | 1435 | return NULL; /* error */ | |
1439 | 1436 | |||
1440 | if ((he = el_malloc(sizeof(*he))) == NULL) | 1437 | if ((he = el_malloc(sizeof(*he))) == NULL) | |
1441 | return NULL; | 1438 | return NULL; | |
1442 | 1439 | |||
1443 | /* look forwards for event matching specified offset */ | 1440 | /* look forwards for event matching specified offset */ | |
1444 | if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) | 1441 | if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) | |
1445 | goto out; | 1442 | goto out; | |
1446 | 1443 | |||
1447 | he->line = strdup(ev.str); | 1444 | he->line = strdup(ev.str); | |
1448 | if (he->line == NULL) | 1445 | if (he->line == NULL) | |
1449 | goto out; | 1446 | goto out; | |
1450 | 1447 | |||
1451 | if (history(h, &ev, H_REPLACE, line, data)) | 1448 | if (history(h, &ev, H_REPLACE, line, data)) | |
1452 | goto out; | 1449 | goto out; | |
1453 | 1450 | |||
1454 | /* restore pointer to where it was */ | 1451 | /* restore pointer to where it was */ | |
1455 | if (history(h, &ev, H_SET, curr_num)) | 1452 | if (history(h, &ev, H_SET, curr_num)) | |
1456 | goto out; | 1453 | goto out; | |
1457 | 1454 | |||
1458 | return he; | 1455 | return he; | |
1459 | out: | 1456 | out: | |
1460 | el_free(he); | 1457 | el_free(he); | |
1461 | return NULL; | 1458 | return NULL; | |
1462 | } | 1459 | } | |
1463 | 1460 | |||
1464 | /* | 1461 | /* | |
1465 | * clear the history list - delete all entries | 1462 | * clear the history list - delete all entries | |
1466 | */ | 1463 | */ | |
1467 | void | 1464 | void | |
1468 | clear_history(void) | 1465 | clear_history(void) | |
1469 | { | 1466 | { | |
1470 | HistEvent ev; | 1467 | HistEvent ev; | |
1471 | 1468 | |||
1472 | (void)history(h, &ev, H_CLEAR); | 1469 | (void)history(h, &ev, H_CLEAR); | |
1473 | history_length = 0; | 1470 | history_length = 0; | |
1474 | } | 1471 | } | |
1475 | 1472 | |||
1476 | 1473 | |||
1477 | /* | 1474 | /* | |
1478 | * returns offset of the current history event | 1475 | * returns offset of the current history event | |
1479 | */ | 1476 | */ | |
1480 | int | 1477 | int | |
1481 | where_history(void) | 1478 | where_history(void) | |
1482 | { | 1479 | { | |
1483 | HistEvent ev; | 1480 | HistEvent ev; | |
1484 | int curr_num, off; | 1481 | int curr_num, off; | |
1485 | 1482 | |||
1486 | if (history(h, &ev, H_CURR) != 0) | 1483 | if (history(h, &ev, H_CURR) != 0) | |
1487 | return 0; | 1484 | return 0; | |
1488 | curr_num = ev.num; | 1485 | curr_num = ev.num; | |
1489 | 1486 | |||
1490 | (void)history(h, &ev, H_FIRST); | 1487 | (void)history(h, &ev, H_FIRST); | |
1491 | off = 1; | 1488 | off = 1; | |
1492 | while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) | 1489 | while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) | |
1493 | off++; | 1490 | off++; | |
1494 | 1491 | |||
1495 | return off; | 1492 | return off; | |
1496 | } | 1493 | } | |
1497 | 1494 | |||
1498 | 1495 | |||
1499 | /* | 1496 | /* | |
1500 | * returns current history event or NULL if there is no such event | 1497 | * returns current history event or NULL if there is no such event | |
1501 | */ | 1498 | */ | |
1502 | HIST_ENTRY * | 1499 | HIST_ENTRY * | |
1503 | current_history(void) | 1500 | current_history(void) | |
1504 | { | 1501 | { | |
1505 | 1502 | |||
1506 | return _move_history(H_CURR); | 1503 | return _move_history(H_CURR); | |
1507 | } | 1504 | } | |
1508 | 1505 | |||
1509 | 1506 | |||
1510 | /* | 1507 | /* | |
1511 | * returns total number of bytes history events' data are using | 1508 | * returns total number of bytes history events' data are using | |
1512 | */ | 1509 | */ | |
1513 | int | 1510 | int | |
1514 | history_total_bytes(void) | 1511 | history_total_bytes(void) | |
1515 | { | 1512 | { | |
1516 | HistEvent ev; | 1513 | HistEvent ev; | |
1517 | int curr_num; | 1514 | int curr_num; | |
1518 | size_t size; | 1515 | size_t size; | |
1519 | 1516 | |||
1520 | if (history(h, &ev, H_CURR) != 0) | 1517 | if (history(h, &ev, H_CURR) != 0) | |
1521 | return -1; | 1518 | return -1; | |
1522 | curr_num = ev.num; | 1519 | curr_num = ev.num; | |
1523 | 1520 | |||
1524 | (void)history(h, &ev, H_FIRST); | 1521 | (void)history(h, &ev, H_FIRST); | |
1525 | size = 0; | 1522 | size = 0; | |
1526 | do | 1523 | do | |
1527 | size += strlen(ev.str) * sizeof(*ev.str); | 1524 | size += strlen(ev.str) * sizeof(*ev.str); | |
1528 | while (history(h, &ev, H_NEXT) == 0); | 1525 | while (history(h, &ev, H_NEXT) == 0); | |
1529 | 1526 | |||
1530 | /* get to the same position as before */ | 1527 | /* get to the same position as before */ | |
1531 | history(h, &ev, H_PREV_EVENT, curr_num); | 1528 | history(h, &ev, H_PREV_EVENT, curr_num); | |
1532 | 1529 | |||
1533 | return (int)size; | 1530 | return (int)size; | |
1534 | } | 1531 | } | |
1535 | 1532 | |||
1536 | 1533 | |||
1537 | /* | 1534 | /* | |
1538 | * sets the position in the history list to ``pos'' | 1535 | * sets the position in the history list to ``pos'' | |
1539 | */ | 1536 | */ | |
1540 | int | 1537 | int | |
1541 | history_set_pos(int pos) | 1538 | history_set_pos(int pos) | |
1542 | { | 1539 | { | |
1543 | HistEvent ev; | 1540 | HistEvent ev; | |
1544 | int curr_num; | 1541 | int curr_num; | |
1545 | 1542 | |||
1546 | if (pos >= history_length || pos < 0) | 1543 | if (pos >= history_length || pos < 0) | |
1547 | return -1; | 1544 | return -1; | |
1548 | 1545 | |||
1549 | (void)history(h, &ev, H_CURR); | 1546 | (void)history(h, &ev, H_CURR); | |
1550 | curr_num = ev.num; | 1547 | curr_num = ev.num; | |
1551 | 1548 | |||
1552 | /* | 1549 | /* | |
1553 | * use H_DELDATA to set to nth history (without delete) by passing | 1550 | * use H_DELDATA to set to nth history (without delete) by passing | |
1554 | * (void **)-1 | 1551 | * (void **)-1 | |
1555 | */ | 1552 | */ | |
1556 | if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { | 1553 | if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { | |
1557 | (void)history(h, &ev, H_SET, curr_num); | 1554 | (void)history(h, &ev, H_SET, curr_num); | |
1558 | return -1; | 1555 | return -1; | |
1559 | } | 1556 | } | |
1560 | return 0; | 1557 | return 0; | |
1561 | } | 1558 | } | |
1562 | 1559 | |||
1563 | 1560 | |||
1564 | /* | 1561 | /* | |
1565 | * returns previous event in history and shifts pointer accordingly | 1562 | * returns previous event in history and shifts pointer accordingly | |
1566 | */ | 1563 | */ | |
1567 | HIST_ENTRY * | 1564 | HIST_ENTRY * | |
1568 | previous_history(void) | 1565 | previous_history(void) | |
1569 | { | 1566 | { | |
1570 | 1567 | |||
1571 | return _move_history(H_PREV); | 1568 | return _move_history(H_PREV); | |
1572 | } | 1569 | } | |
1573 | 1570 | |||
1574 | 1571 | |||
1575 | /* | 1572 | /* | |
1576 | * returns next event in history and shifts pointer accordingly | 1573 | * returns next event in history and shifts pointer accordingly | |
1577 | */ | 1574 | */ | |
1578 | HIST_ENTRY * | 1575 | HIST_ENTRY * | |
1579 | next_history(void) | 1576 | next_history(void) | |
1580 | { | 1577 | { | |
1581 | 1578 | |||
1582 | return _move_history(H_NEXT); | 1579 | return _move_history(H_NEXT); | |
1583 | } | 1580 | } | |
1584 | 1581 | |||
1585 | 1582 | |||
1586 | /* | 1583 | /* | |
1587 | * searches for first history event containing the str | 1584 | * searches for first history event containing the str | |
1588 | */ | 1585 | */ | |
1589 | int | 1586 | int | |
1590 | history_search(const char *str, int direction) | 1587 | history_search(const char *str, int direction) | |
1591 | { | 1588 | { | |
1592 | HistEvent ev; | 1589 | HistEvent ev; | |
1593 | const char *strp; | 1590 | const char *strp; | |
1594 | int curr_num; | 1591 | int curr_num; | |
1595 | 1592 | |||
1596 | if (history(h, &ev, H_CURR) != 0) | 1593 | if (history(h, &ev, H_CURR) != 0) | |
1597 | return -1; | 1594 | return -1; | |
1598 | curr_num = ev.num; | 1595 | curr_num = ev.num; | |
1599 | 1596 | |||
1600 | for (;;) { | 1597 | for (;;) { | |
1601 | if ((strp = strstr(ev.str, str)) != NULL) | 1598 | if ((strp = strstr(ev.str, str)) != NULL) | |
1602 | return (int)(strp - ev.str); | 1599 | return (int)(strp - ev.str); | |
1603 | if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) | 1600 | if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) | |
1604 | break; | 1601 | break; | |
1605 | } | 1602 | } | |
1606 | (void)history(h, &ev, H_SET, curr_num); | 1603 | (void)history(h, &ev, H_SET, curr_num); | |
1607 | return -1; | 1604 | return -1; | |
1608 | } | 1605 | } | |
1609 | 1606 | |||
1610 | 1607 | |||
1611 | /* | 1608 | /* | |
1612 | * searches for first history event beginning with str | 1609 | * searches for first history event beginning with str | |
1613 | */ | 1610 | */ | |
1614 | int | 1611 | int | |
1615 | history_search_prefix(const char *str, int direction) | 1612 | history_search_prefix(const char *str, int direction) | |
1616 | { | 1613 | { | |
1617 | HistEvent ev; | 1614 | HistEvent ev; | |
1618 | 1615 | |||
1619 | return (history(h, &ev, direction < 0 ? | 1616 | return (history(h, &ev, direction < 0 ? | |
1620 | H_PREV_STR : H_NEXT_STR, str)); | 1617 | H_PREV_STR : H_NEXT_STR, str)); | |
1621 | } | 1618 | } | |
1622 | 1619 | |||
1623 | 1620 | |||
1624 | /* | 1621 | /* | |
1625 | * search for event in history containing str, starting at offset | 1622 | * search for event in history containing str, starting at offset | |
1626 | * abs(pos); continue backward, if pos<0, forward otherwise | 1623 | * abs(pos); continue backward, if pos<0, forward otherwise | |
1627 | */ | 1624 | */ | |
1628 | /* ARGSUSED */ | 1625 | /* ARGSUSED */ | |
1629 | int | 1626 | int | |
1630 | history_search_pos(const char *str, | 1627 | history_search_pos(const char *str, | |
1631 | int direction __attribute__((__unused__)), int pos) | 1628 | int direction __attribute__((__unused__)), int pos) | |
1632 | { | 1629 | { | |
1633 | HistEvent ev; | 1630 | HistEvent ev; | |
1634 | int curr_num, off; | 1631 | int curr_num, off; | |
1635 | 1632 | |||
1636 | off = (pos > 0) ? pos : -pos; | 1633 | off = (pos > 0) ? pos : -pos; | |
1637 | pos = (pos > 0) ? 1 : -1; | 1634 | pos = (pos > 0) ? 1 : -1; | |
1638 | 1635 | |||
1639 | if (history(h, &ev, H_CURR) != 0) | 1636 | if (history(h, &ev, H_CURR) != 0) | |
1640 | return -1; | 1637 | return -1; | |
1641 | curr_num = ev.num; | 1638 | curr_num = ev.num; | |
1642 | 1639 | |||
1643 | if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) | 1640 | if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) | |
1644 | return -1; | 1641 | return -1; | |
1645 | 1642 | |||
1646 | for (;;) { | 1643 | for (;;) { | |
1647 | if (strstr(ev.str, str)) | 1644 | if (strstr(ev.str, str)) | |
1648 | return off; | 1645 | return off; | |
1649 | if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) | 1646 | if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) | |
1650 | break; | 1647 | break; | |
1651 | } | 1648 | } | |
1652 | 1649 | |||
1653 | /* set "current" pointer back to previous state */ | 1650 | /* set "current" pointer back to previous state */ | |
1654 | (void)history(h, &ev, | 1651 | (void)history(h, &ev, | |
1655 | pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); | 1652 | pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); | |
1656 | 1653 | |||
1657 | return -1; | 1654 | return -1; | |
1658 | } | 1655 | } | |
1659 | 1656 | |||
1660 | 1657 | |||
1661 | /********************************/ | 1658 | /********************************/ | |
1662 | /* completion functions */ | 1659 | /* completion functions */ | |
1663 | 1660 | |||
1664 | char * | 1661 | char * | |
1665 | tilde_expand(char *name) | 1662 | tilde_expand(char *name) | |
1666 | { | 1663 | { | |
1667 | return fn_tilde_expand(name); | 1664 | return fn_tilde_expand(name); | |
1668 | } | 1665 | } | |
1669 | 1666 | |||
1670 | char * | 1667 | char * | |
1671 | filename_completion_function(const char *name, int state) | 1668 | filename_completion_function(const char *name, int state) | |
1672 | { | 1669 | { | |
1673 | return fn_filename_completion_function(name, state); | 1670 | return fn_filename_completion_function(name, state); | |
1674 | } | 1671 | } | |
1675 | 1672 | |||
1676 | /* | 1673 | /* | |
1677 | * a completion generator for usernames; returns _first_ username | 1674 | * a completion generator for usernames; returns _first_ username | |
1678 | * which starts with supplied text | 1675 | * which starts with supplied text | |
1679 | * text contains a partial username preceded by random character | 1676 | * text contains a partial username preceded by random character | |
1680 | * (usually '~'); state resets search from start (??? should we do that anyway) | 1677 | * (usually '~'); state resets search from start (??? should we do that anyway) | |
1681 | * it's callers responsibility to free returned value | 1678 | * it's callers responsibility to free returned value | |
1682 | */ | 1679 | */ | |
1683 | char * | 1680 | char * | |
1684 | username_completion_function(const char *text, int state) | 1681 | username_completion_function(const char *text, int state) | |
1685 | { | 1682 | { | |
1686 | #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) | 1683 | #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) | |
1687 | struct passwd pwres; | 1684 | struct passwd pwres; | |
1688 | char pwbuf[1024]; | 1685 | char pwbuf[1024]; | |
1689 | #endif | 1686 | #endif | |
1690 | struct passwd *pass = NULL; | 1687 | struct passwd *pass = NULL; | |
1691 | 1688 | |||
1692 | if (text[0] == '\0') | 1689 | if (text[0] == '\0') | |
1693 | return NULL; | 1690 | return NULL; | |
1694 | 1691 | |||
1695 | if (*text == '~') | 1692 | if (*text == '~') | |
1696 | text++; | 1693 | text++; | |
1697 | 1694 | |||
1698 | if (state == 0) | 1695 | if (state == 0) | |
1699 | setpwent(); | 1696 | setpwent(); | |
1700 | 1697 | |||
1701 | while ( | 1698 | while ( | |
1702 | #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) | 1699 | #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) | |
1703 | getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pass) == 0 && pass != NULL | 1700 | getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pass) == 0 && pass != NULL | |
1704 | #else | 1701 | #else | |
1705 | (pass = getpwent()) != NULL | 1702 | (pass = getpwent()) != NULL | |
1706 | #endif | 1703 | #endif | |
1707 | && text[0] == pass->pw_name[0] | 1704 | && text[0] == pass->pw_name[0] | |
1708 | && strcmp(text, pass->pw_name) == 0) | 1705 | && strcmp(text, pass->pw_name) == 0) | |
1709 | continue; | 1706 | continue; | |
1710 | 1707 | |||
1711 | if (pass == NULL) { | 1708 | if (pass == NULL) { | |
1712 | endpwent(); | 1709 | endpwent(); | |
1713 | return NULL; | 1710 | return NULL; | |
1714 | } | 1711 | } | |
1715 | return strdup(pass->pw_name); | 1712 | return strdup(pass->pw_name); | |
1716 | } | 1713 | } | |
1717 | 1714 | |||
1718 | 1715 | |||
1719 | /* | 1716 | /* | |
1720 | * el-compatible wrapper to send TSTP on ^Z | 1717 | * el-compatible wrapper to send TSTP on ^Z | |
1721 | */ | 1718 | */ | |
1722 | /* ARGSUSED */ | 1719 | /* ARGSUSED */ | |
1723 | static unsigned char | 1720 | static unsigned char | |
1724 | _el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) | 1721 | _el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) | |
1725 | { | 1722 | { | |
1726 | (void)kill(0, SIGTSTP); | 1723 | (void)kill(0, SIGTSTP); | |
1727 | return CC_NORM; | 1724 | return CC_NORM; | |
1728 | } | 1725 | } | |
1729 | 1726 | |||
1730 | /* | 1727 | /* | |
1731 | * Display list of strings in columnar format on readline's output stream. | 1728 | * Display list of strings in columnar format on readline's output stream. | |
1732 | * 'matches' is list of strings, 'len' is number of strings in 'matches', | 1729 | * 'matches' is list of strings, 'len' is number of strings in 'matches', | |
1733 | * 'max' is maximum length of string in 'matches'. | 1730 | * 'max' is maximum length of string in 'matches'. | |
1734 | */ | 1731 | */ | |
1735 | void | 1732 | void | |
1736 | rl_display_match_list(char **matches, int len, int max) | 1733 | rl_display_match_list(char **matches, int len, int max) | |
1737 | { | 1734 | { | |
1738 | 1735 | |||
1739 | fn_display_match_list(e, matches, (size_t)len, (size_t)max); | 1736 | fn_display_match_list(e, matches, (size_t)len, (size_t)max); | |
1740 | } | 1737 | } | |
1741 | 1738 | |||
1742 | static const char * | 1739 | static const char * | |
1743 | /*ARGSUSED*/ | 1740 | /*ARGSUSED*/ | |
1744 | _rl_completion_append_character_function(const char *dummy | 1741 | _rl_completion_append_character_function(const char *dummy | |
1745 | __attribute__((__unused__))) | 1742 | __attribute__((__unused__))) | |
1746 | { | 1743 | { | |
1747 | static char buf[2]; | 1744 | static char buf[2]; | |
1748 | buf[0] = rl_completion_append_character; | 1745 | buf[0] = rl_completion_append_character; | |
1749 | buf[1] = '\0'; | 1746 | buf[1] = '\0'; | |
1750 | return buf; | 1747 | return buf; | |
1751 | } | 1748 | } | |
1752 | 1749 | |||
1753 | 1750 | |||
1754 | /* | 1751 | /* | |
1755 | * complete word at current point | 1752 | * complete word at current point | |
1756 | */ | 1753 | */ | |
1757 | /* ARGSUSED */ | 1754 | /* ARGSUSED */ | |
1758 | int | 1755 | int | |
1759 | rl_complete(int ignore __attribute__((__unused__)), int invoking_key) | 1756 | rl_complete(int ignore __attribute__((__unused__)), int invoking_key) | |
1760 | { | 1757 | { | |
1761 | #ifdef WIDECHAR | 1758 | #ifdef WIDECHAR | |
1762 | static ct_buffer_t wbreak_conv, sprefix_conv; | 1759 | static ct_buffer_t wbreak_conv, sprefix_conv; | |
1763 | #endif | 1760 | #endif | |
1764 | 1761 | |||
1765 | if (h == NULL || e == NULL) | 1762 | if (h == NULL || e == NULL) | |
1766 | rl_initialize(); | 1763 | rl_initialize(); | |
1767 | 1764 | |||
1768 | if (rl_inhibit_completion) { | 1765 | if (rl_inhibit_completion) { | |
1769 | char arr[2]; | 1766 | char arr[2]; | |
1770 | arr[0] = (char)invoking_key; | 1767 | arr[0] = (char)invoking_key; | |
1771 | arr[1] = '\0'; | 1768 | arr[1] = '\0'; | |
1772 | el_insertstr(e, arr); | 1769 | el_insertstr(e, arr); | |
1773 | return CC_REFRESH; | 1770 | return CC_REFRESH; | |
1774 | } | 1771 | } | |
1775 | 1772 | |||
1776 | /* Just look at how many global variables modify this operation! */ | 1773 | /* Just look at how many global variables modify this operation! */ | |
1777 | return fn_complete(e, | 1774 | return fn_complete(e, | |
1778 | (CPFunction *)rl_completion_entry_function, | 1775 | (CPFunction *)rl_completion_entry_function, | |
1779 | rl_attempted_completion_function, | 1776 | rl_attempted_completion_function, | |
1780 | ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), | 1777 | ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), | |
1781 | ct_decode_string(rl_special_prefixes, &sprefix_conv), | 1778 | ct_decode_string(rl_special_prefixes, &sprefix_conv), | |
1782 | _rl_completion_append_character_function, | 1779 | _rl_completion_append_character_function, | |
1783 | (size_t)rl_completion_query_items, | 1780 | (size_t)rl_completion_query_items, | |
1784 | &rl_completion_type, &rl_attempted_completion_over, | 1781 | &rl_completion_type, &rl_attempted_completion_over, | |
1785 | &rl_point, &rl_end); | 1782 | &rl_point, &rl_end); | |
1786 | 1783 | |||
1787 | 1784 | |||
1788 | } | 1785 | } | |
1789 | 1786 | |||
1790 | 1787 | |||
1791 | /* ARGSUSED */ | 1788 | /* ARGSUSED */ | |
1792 | static unsigned char | 1789 | static unsigned char | |
1793 | _el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) | 1790 | _el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) | |
1794 | { | 1791 | { | |
1795 | return (unsigned char)rl_complete(0, ch); | 1792 | return (unsigned char)rl_complete(0, ch); | |
1796 | } | 1793 | } | |
1797 | 1794 | |||
1798 | /* | 1795 | /* | |
1799 | * misc other functions | 1796 | * misc other functions | |
1800 | */ | 1797 | */ | |
1801 | 1798 | |||
1802 | /* | 1799 | /* | |
1803 | * bind key c to readline-type function func | 1800 | * bind key c to readline-type function func | |
1804 | */ | 1801 | */ | |
1805 | int | 1802 | int | |
1806 | rl_bind_key(int c, rl_command_func_t *func) | 1803 | rl_bind_key(int c, rl_command_func_t *func) | |
1807 | { | 1804 | { | |
1808 | int retval = -1; | 1805 | int retval = -1; | |
1809 | 1806 | |||
1810 | if (h == NULL || e == NULL) | 1807 | if (h == NULL || e == NULL) | |
1811 | rl_initialize(); | 1808 | rl_initialize(); | |
1812 | 1809 | |||
1813 | if (func == rl_insert) { | 1810 | if (func == rl_insert) { | |
1814 | /* XXX notice there is no range checking of ``c'' */ | 1811 | /* XXX notice there is no range checking of ``c'' */ | |
1815 | e->el_map.key[c] = ED_INSERT; | 1812 | e->el_map.key[c] = ED_INSERT; | |
1816 | retval = 0; | 1813 | retval = 0; | |
1817 | } | 1814 | } | |
1818 | return retval; | 1815 | return retval; | |
1819 | } | 1816 | } | |
1820 | 1817 | |||
1821 | 1818 | |||
1822 | /* | 1819 | /* | |
1823 | * read one key from input - handles chars pushed back | 1820 | * read one key from input - handles chars pushed back | |
1824 | * to input stream also | 1821 | * to input stream also | |
1825 | */ | 1822 | */ | |
1826 | int | 1823 | int | |
1827 | rl_read_key(void) | 1824 | rl_read_key(void) | |
1828 | { | 1825 | { | |
1829 | char fooarr[2 * sizeof(int)]; | 1826 | char fooarr[2 * sizeof(int)]; | |
1830 | 1827 | |||
1831 | if (e == NULL || h == NULL) | 1828 | if (e == NULL || h == NULL) | |
1832 | rl_initialize(); | 1829 | rl_initialize(); | |
1833 | 1830 | |||
1834 | return el_getc(e, fooarr); | 1831 | return el_getc(e, fooarr); | |
1835 | } | 1832 | } | |
1836 | 1833 | |||
1837 | 1834 | |||
1838 | /* | 1835 | /* | |
1839 | * reset the terminal | 1836 | * reset the terminal | |
1840 | */ | 1837 | */ | |
1841 | /* ARGSUSED */ | 1838 | /* ARGSUSED */ | |
1842 | void | 1839 | void | |
1843 | rl_reset_terminal(const char *p __attribute__((__unused__))) | 1840 | rl_reset_terminal(const char *p __attribute__((__unused__))) | |
1844 | { | 1841 | { | |
1845 | 1842 | |||
1846 | if (h == NULL || e == NULL) | 1843 | if (h == NULL || e == NULL) | |
1847 | rl_initialize(); | 1844 | rl_initialize(); | |
1848 | el_reset(e); | 1845 | el_reset(e); | |
1849 | } | 1846 | } | |
1850 | 1847 | |||
1851 | 1848 | |||
1852 | /* | 1849 | /* | |
1853 | * insert character ``c'' back into input stream, ``count'' times | 1850 | * insert character ``c'' back into input stream, ``count'' times | |
1854 | */ | 1851 | */ | |
1855 | int | 1852 | int | |
1856 | rl_insert(int count, int c) | 1853 | rl_insert(int count, int c) | |
1857 | { | 1854 | { | |
1858 | char arr[2]; | 1855 | char arr[2]; | |
1859 | 1856 | |||
1860 | if (h == NULL || e == NULL) | 1857 | if (h == NULL || e == NULL) | |
1861 | rl_initialize(); | 1858 | rl_initialize(); | |
1862 | 1859 | |||
1863 | /* XXX - int -> char conversion can lose on multichars */ | 1860 | /* XXX - int -> char conversion can lose on multichars */ | |
1864 | arr[0] = c; | 1861 | arr[0] = c; | |
1865 | arr[1] = '\0'; | 1862 | arr[1] = '\0'; | |
1866 | 1863 | |||
1867 | for (; count > 0; count--) | 1864 | for (; count > 0; count--) | |
1868 | el_push(e, arr); | 1865 | el_push(e, arr); | |
1869 | 1866 | |||
1870 | return 0; | 1867 | return 0; | |
1871 | } | 1868 | } | |
1872 | 1869 | |||
1873 | int | 1870 | int | |
1874 | rl_insert_text(const char *text) | 1871 | rl_insert_text(const char *text) | |
1875 | { | 1872 | { | |
1876 | if (!text || *text == 0) | 1873 | if (!text || *text == 0) | |
1877 | return 0; | 1874 | return 0; | |
1878 | 1875 | |||
1879 | if (h == NULL || e == NULL) | 1876 | if (h == NULL || e == NULL) | |
1880 | rl_initialize(); | 1877 | rl_initialize(); | |
1881 | 1878 | |||
1882 | if (el_insertstr(e, text) < 0) | 1879 | if (el_insertstr(e, text) < 0) | |
1883 | return 0; | 1880 | return 0; | |
1884 | return (int)strlen(text); | 1881 | return (int)strlen(text); | |
1885 | } | 1882 | } | |
1886 | 1883 | |||
1887 | /*ARGSUSED*/ | 1884 | /*ARGSUSED*/ | |
1888 | int | 1885 | int | |
1889 | rl_newline(int count, int c) | 1886 | rl_newline(int count __attribute__((__unused__)), | |
1887 | int c __attribute__((__unused__))) | |||
1890 | { | 1888 | { | |
1891 | /* | 1889 | /* | |
1892 | * Readline-4.0 appears to ignore the args. | 1890 | * Readline-4.0 appears to ignore the args. | |
1893 | */ | 1891 | */ | |
1894 | return rl_insert(1, '\n'); | 1892 | return rl_insert(1, '\n'); | |
1895 | } | 1893 | } | |
1896 | 1894 | |||
1897 | /*ARGSUSED*/ | 1895 | /*ARGSUSED*/ | |
1898 | static unsigned char | 1896 | static unsigned char | |
1899 | rl_bind_wrapper(EditLine *el, unsigned char c) | 1897 | rl_bind_wrapper(EditLine *el __attribute__((__unused__)), unsigned char c) | |
1900 | { | 1898 | { | |
1901 | if (map[c] == NULL) | 1899 | if (map[c] == NULL) | |
1902 | return CC_ERROR; | 1900 | return CC_ERROR; | |
1903 | 1901 | |||
1904 | _rl_update_pos(); | 1902 | _rl_update_pos(); | |
1905 | 1903 | |||
1906 | (*map[c])(NULL, c); | 1904 | (*map[c])(NULL, c); | |
1907 | 1905 | |||
1908 | /* If rl_done was set by the above call, deal with it here */ | 1906 | /* If rl_done was set by the above call, deal with it here */ | |
1909 | if (rl_done) | 1907 | if (rl_done) | |
1910 | return CC_EOF; | 1908 | return CC_EOF; | |
1911 | 1909 | |||
1912 | return CC_NORM; | 1910 | return CC_NORM; | |
1913 | } | 1911 | } | |
1914 | 1912 | |||
1915 | int | 1913 | int | |
1916 | rl_add_defun(const char *name, Function *fun, int c) | 1914 | rl_add_defun(const char *name, Function *fun, int c) | |
1917 | { | 1915 | { | |
1918 | char dest[8]; | 1916 | char dest[8]; | |
1919 | if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) | 1917 | if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) | |
1920 | return -1; | 1918 | return -1; | |
1921 | map[(unsigned char)c] = fun; | 1919 | map[(unsigned char)c] = fun; | |
1922 | el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); | 1920 | el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); | |
1923 | vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); | 1921 | vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); | |
1924 | el_set(e, EL_BIND, dest, name); | 1922 | el_set(e, EL_BIND, dest, name); | |
1925 | return 0; | 1923 | return 0; | |
1926 | } | 1924 | } | |
1927 | 1925 | |||
1928 | void | 1926 | void | |
1929 | rl_callback_read_char() | 1927 | rl_callback_read_char() | |
1930 | { | 1928 | { | |
1931 | int count = 0, done = 0; | 1929 | int count = 0, done = 0; | |
1932 | const char *buf = el_gets(e, &count); | 1930 | const char *buf = el_gets(e, &count); | |
1933 | char *wbuf; | 1931 | char *wbuf; | |
1934 | 1932 | |||
1935 | if (buf == NULL || count-- <= 0) | 1933 | if (buf == NULL || count-- <= 0) | |
1936 | return; | 1934 | return; | |
1937 | if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF]) | 1935 | if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF]) | |
1938 | done = 1; | 1936 | done = 1; | |
1939 | if (buf[count] == '\n' || buf[count] == '\r') | 1937 | if (buf[count] == '\n' || buf[count] == '\r') | |
1940 | done = 2; | 1938 | done = 2; | |
1941 | 1939 | |||
1942 | if (done && rl_linefunc != NULL) { | 1940 | if (done && rl_linefunc != NULL) { | |
1943 | el_set(e, EL_UNBUFFERED, 0); | 1941 | el_set(e, EL_UNBUFFERED, 0); | |
1944 | if (done == 2) { | 1942 | if (done == 2) { | |
1945 | if ((wbuf = strdup(buf)) != NULL) | 1943 | if ((wbuf = strdup(buf)) != NULL) | |
1946 | wbuf[count] = '\0'; | 1944 | wbuf[count] = '\0'; | |
1947 | } else | 1945 | } else | |
1948 | wbuf = NULL; | 1946 | wbuf = NULL; | |
1949 | (*(void (*)(const char *))rl_linefunc)(wbuf); | 1947 | (*(void (*)(const char *))rl_linefunc)(wbuf); | |
1950 | //el_set(e, EL_UNBUFFERED, 1); | 1948 | //el_set(e, EL_UNBUFFERED, 1); | |
1951 | } | 1949 | } | |
1952 | } | 1950 | } | |
1953 | 1951 | |||
1954 | void | 1952 | void | |
1955 | rl_callback_handler_install(const char *prompt, VCPFunction *linefunc) | 1953 | rl_callback_handler_install(const char *prompt, VCPFunction *linefunc) | |
1956 | { | 1954 | { | |
1957 | if (e == NULL) { | 1955 | if (e == NULL) { | |
1958 | rl_initialize(); | 1956 | rl_initialize(); | |
1959 | } | 1957 | } | |
1960 | (void)rl_set_prompt(prompt); | 1958 | (void)rl_set_prompt(prompt); | |
1961 | rl_linefunc = linefunc; | 1959 | rl_linefunc = linefunc; | |
1962 | el_set(e, EL_UNBUFFERED, 1); | 1960 | el_set(e, EL_UNBUFFERED, 1); | |
1963 | } | 1961 | } | |
1964 | 1962 | |||
1965 | void | 1963 | void | |
1966 | rl_callback_handler_remove(void) | 1964 | rl_callback_handler_remove(void) | |
1967 | { | 1965 | { | |
1968 | el_set(e, EL_UNBUFFERED, 0); | 1966 | el_set(e, EL_UNBUFFERED, 0); | |
1969 | rl_linefunc = NULL; | 1967 | rl_linefunc = NULL; | |
1970 | } | 1968 | } | |
1971 | 1969 | |||
1972 | void | 1970 | void | |
1973 | rl_redisplay(void) | 1971 | rl_redisplay(void) | |
1974 | { | 1972 | { | |
1975 | char a[2]; | 1973 | char a[2]; | |
1976 | a[0] = e->el_tty.t_c[TS_IO][C_REPRINT]; | 1974 | a[0] = e->el_tty.t_c[TS_IO][C_REPRINT]; | |
1977 | a[1] = '\0'; | 1975 | a[1] = '\0'; | |
1978 | el_push(e, a); | 1976 | el_push(e, a); | |
1979 | } | 1977 | } | |
1980 | 1978 | |||
1981 | int | 1979 | int | |
1982 | rl_get_previous_history(int count, int key) | 1980 | rl_get_previous_history(int count, int key) | |
1983 | { | 1981 | { | |
1984 | char a[2]; | 1982 | char a[2]; | |
1985 | a[0] = key; | 1983 | a[0] = key; | |
1986 | a[1] = '\0'; | 1984 | a[1] = '\0'; | |
1987 | while (count--) | 1985 | while (count--) | |
1988 | el_push(e, a); | 1986 | el_push(e, a); | |
1989 | return 0; | 1987 | return 0; | |
1990 | } | 1988 | } | |
1991 | 1989 | |||
1992 | void | 1990 | void | |
1993 | /*ARGSUSED*/ | 1991 | /*ARGSUSED*/ | |
1994 | rl_prep_terminal(int meta_flag) | 1992 | rl_prep_terminal(int meta_flag __attribute__((__unused__))) | |
1995 | { | 1993 | { | |
1996 | el_set(e, EL_PREP_TERM, 1); | 1994 | el_set(e, EL_PREP_TERM, 1); | |
1997 | } | 1995 | } | |
1998 | 1996 | |||
1999 | void | 1997 | void | |
2000 | rl_deprep_terminal(void) | 1998 | rl_deprep_terminal(void) | |
2001 | { | 1999 | { | |
2002 | el_set(e, EL_PREP_TERM, 0); | 2000 | el_set(e, EL_PREP_TERM, 0); | |
2003 | } | 2001 | } | |
2004 | 2002 | |||
2005 | int | 2003 | int | |
2006 | rl_read_init_file(const char *s) | 2004 | rl_read_init_file(const char *s) | |
2007 | { | 2005 | { | |
2008 | return el_source(e, s); | 2006 | return el_source(e, s); | |
2009 | } | 2007 | } | |
2010 | 2008 | |||
2011 | int | 2009 | int | |
2012 | rl_parse_and_bind(const char *line) | 2010 | rl_parse_and_bind(const char *line) | |
2013 | { | 2011 | { | |
2014 | const char **argv; | 2012 | const char **argv; | |
2015 | int argc; | 2013 | int argc; | |
2016 | Tokenizer *tok; | 2014 | Tokenizer *tok; | |
2017 | 2015 | |||
2018 | tok = tok_init(NULL); | 2016 | tok = tok_init(NULL); | |
2019 | tok_str(tok, line, &argc, &argv); | 2017 | tok_str(tok, line, &argc, &argv); | |
2020 | argc = el_parse(e, argc, argv); | 2018 | argc = el_parse(e, argc, argv); | |
2021 | tok_end(tok); | 2019 | tok_end(tok); | |
2022 | return argc ? 1 : 0; | 2020 | return argc ? 1 : 0; | |
2023 | } | 2021 | } | |
2024 | 2022 | |||
2025 | int | 2023 | int | |
2026 | rl_variable_bind(const char *var, const char *value) | 2024 | rl_variable_bind(const char *var, const char *value) | |
2027 | { | 2025 | { | |
2028 | /* | 2026 | /* | |
2029 | * The proper return value is undocument, but this is what the | 2027 | * The proper return value is undocument, but this is what the | |
2030 | * readline source seems to do. | 2028 | * readline source seems to do. | |
2031 | */ | 2029 | */ | |
2032 | return el_set(e, EL_BIND, "", var, value) == -1 ? 1 : 0; | 2030 | return el_set(e, EL_BIND, "", var, value) == -1 ? 1 : 0; | |
2033 | } | 2031 | } | |
2034 | 2032 | |||
2035 | void | 2033 | void | |
2036 | rl_stuff_char(int c) | 2034 | rl_stuff_char(int c) | |
2037 | { | 2035 | { | |
2038 | char buf[2]; | 2036 | char buf[2]; | |
2039 | 2037 | |||
2040 | buf[0] = c; | 2038 | buf[0] = c; | |
2041 | buf[1] = '\0'; | 2039 | buf[1] = '\0'; | |
2042 | el_insertstr(e, buf); | 2040 | el_insertstr(e, buf); | |
2043 | } | 2041 | } | |
2044 | 2042 | |||
2045 | static int | 2043 | static int | |
2046 | _rl_event_read_char(EditLine *el, char *cp) | 2044 | _rl_event_read_char(EditLine *el, char *cp) | |
2047 | { | 2045 | { | |
2048 | int n; | 2046 | int n; | |
2049 | ssize_t num_read = 0; | 2047 | ssize_t num_read = 0; | |
2050 | 2048 | |||
2051 | *cp = '\0'; | 2049 | *cp = '\0'; | |
2052 | while (rl_event_hook) { | 2050 | while (rl_event_hook) { | |
2053 | 2051 | |||
2054 | (*rl_event_hook)(); | 2052 | (*rl_event_hook)(); | |
2055 | 2053 | |||
2056 | #if defined(FIONREAD) | 2054 | #if defined(FIONREAD) | |
2057 | if (ioctl(el->el_infd, FIONREAD, &n) < 0) | 2055 | if (ioctl(el->el_infd, FIONREAD, &n) < 0) | |
2058 | return -1; | 2056 | return -1; | |
2059 | if (n) | 2057 | if (n) | |
2060 | num_read = read(el->el_infd, cp, 1); | 2058 | num_read = read(el->el_infd, cp, 1); | |
2061 | else | 2059 | else | |
2062 | num_read = 0; | 2060 | num_read = 0; | |
2063 | #elif defined(F_SETFL) && defined(O_NDELAY) | 2061 | #elif defined(F_SETFL) && defined(O_NDELAY) | |
2064 | if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) | 2062 | if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) | |
2065 | return -1; | 2063 | return -1; | |
2066 | if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) | 2064 | if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) | |
2067 | return -1; | 2065 | return -1; | |
2068 | num_read = read(el->el_infd, cp, 1); | 2066 | num_read = read(el->el_infd, cp, 1); | |
2069 | if (fcntl(el->el_infd, F_SETFL, n)) | 2067 | if (fcntl(el->el_infd, F_SETFL, n)) | |
2070 | return -1; | 2068 | return -1; | |
2071 | #else | 2069 | #else | |
2072 | /* not non-blocking, but what you gonna do? */ | 2070 | /* not non-blocking, but what you gonna do? */ | |
2073 | num_read = read(el->el_infd, cp, 1); | 2071 | num_read = read(el->el_infd, cp, 1); | |
2074 | return -1; | 2072 | return -1; | |
2075 | #endif | 2073 | #endif | |
2076 | 2074 | |||
2077 | if (num_read < 0 && errno == EAGAIN) | 2075 | if (num_read < 0 && errno == EAGAIN) | |
2078 | continue; | 2076 | continue; | |
2079 | if (num_read == 0) | 2077 | if (num_read == 0) | |
2080 | continue; | 2078 | continue; | |
2081 | break; | 2079 | break; | |
2082 | } | 2080 | } | |
2083 | if (!rl_event_hook) | 2081 | if (!rl_event_hook) | |
2084 | el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); | 2082 | el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); | |
2085 | return (int)num_read; | 2083 | return (int)num_read; | |
2086 | } | 2084 | } | |
2087 | 2085 | |||
2088 | static void | 2086 | static void | |
2089 | _rl_update_pos(void) | 2087 | _rl_update_pos(void) | |
2090 | { | 2088 | { | |
2091 | const LineInfo *li = el_line(e); | 2089 | const LineInfo *li = el_line(e); | |
2092 | 2090 | |||
2093 | rl_point = (int)(li->cursor - li->buffer); | 2091 | rl_point = (int)(li->cursor - li->buffer); | |
2094 | rl_end = (int)(li->lastchar - li->buffer); | 2092 | rl_end = (int)(li->lastchar - li->buffer); | |
2095 | } | 2093 | } | |
2096 | 2094 | |||
2097 | void | 2095 | void | |
2098 | rl_get_screen_size(int *rows, int *cols) | 2096 | rl_get_screen_size(int *rows, int *cols) | |
2099 | { | 2097 | { | |
2100 | if (rows) | 2098 | if (rows) | |
2101 | el_get(e, EL_GETTC, "li", rows); | 2099 | el_get(e, EL_GETTC, "li", rows); | |
2102 | if (cols) | 2100 | if (cols) | |
2103 | el_get(e, EL_GETTC, "co", cols); | 2101 | el_get(e, EL_GETTC, "co", cols); | |
2104 | } | 2102 | } | |
2105 | 2103 | |||
2106 | void | 2104 | void | |
2107 | rl_set_screen_size(int rows, int cols) | 2105 | rl_set_screen_size(int rows, int cols) | |
2108 | { | 2106 | { | |
2109 | char buf[64]; | 2107 | char buf[64]; | |
2110 | (void)snprintf(buf, sizeof(buf), "%d", rows); | 2108 | (void)snprintf(buf, sizeof(buf), "%d", rows); | |
2111 | el_set(e, EL_SETTC, "li", buf); | 2109 | el_set(e, EL_SETTC, "li", buf); | |
2112 | (void)snprintf(buf, sizeof(buf), "%d", cols); | 2110 | (void)snprintf(buf, sizeof(buf), "%d", cols); | |
2113 | el_set(e, EL_SETTC, "co", buf); | 2111 | el_set(e, EL_SETTC, "co", buf); | |
2114 | } | 2112 | } | |
2115 | 2113 | |||
2116 | char ** | 2114 | char ** | |
2117 | rl_completion_matches(const char *str, rl_compentry_func_t *fun) | 2115 | rl_completion_matches(const char *str, rl_compentry_func_t *fun) | |
2118 | { | 2116 | { | |
2119 | size_t len, max, i, j, min; | 2117 | size_t len, max, i, j, min; | |
2120 | char **list, *match, *a, *b; | 2118 | char **list, *match, *a, *b; | |
2121 | 2119 | |||
2122 | len = 1; | 2120 | len = 1; | |
2123 | max = 10; | 2121 | max = 10; | |
2124 | if ((list = el_malloc(max * sizeof(*list))) == NULL) | 2122 | if ((list = el_malloc(max * sizeof(*list))) == NULL) | |
2125 | return NULL; | 2123 | return NULL; | |
2126 | 2124 | |||
2127 | while ((match = (*fun)(str, (int)(len - 1))) != NULL) { | 2125 | while ((match = (*fun)(str, (int)(len - 1))) != NULL) { | |
2128 | list[len++] = match; | 2126 | list[len++] = match; | |
2129 | if (len == max) { | 2127 | if (len == max) { | |
2130 | char **nl; | 2128 | char **nl; | |
2131 | max += 10; | 2129 | max += 10; | |
2132 | if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL) | 2130 | if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL) | |
2133 | goto out; | 2131 | goto out; | |
2134 | list = nl; | 2132 | list = nl; | |
2135 | } | 2133 | } | |
2136 | } | 2134 | } | |
2137 | if (len == 1) | 2135 | if (len == 1) | |
2138 | goto out; | 2136 | goto out; | |
2139 | list[len] = NULL; | 2137 | list[len] = NULL; | |
2140 | if (len == 2) { | 2138 | if (len == 2) { | |
2141 | if ((list[0] = strdup(list[1])) == NULL) | 2139 | if ((list[0] = strdup(list[1])) == NULL) | |
2142 | goto out; | 2140 | goto out; | |
2143 | return list; | 2141 | return list; | |
2144 | } | 2142 | } | |
2145 | qsort(&list[1], len - 1, sizeof(*list), | 2143 | qsort(&list[1], len - 1, sizeof(*list), | |
2146 | (int (*)(const void *, const void *)) strcmp); | 2144 | (int (*)(const void *, const void *)) strcmp); | |
2147 | min = SIZE_T_MAX; | 2145 | min = SIZE_T_MAX; | |
2148 | for (i = 1, a = list[i]; i < len - 1; i++, a = b) { | 2146 | for (i = 1, a = list[i]; i < len - 1; i++, a = b) { | |
2149 | b = list[i + 1]; | 2147 | b = list[i + 1]; | |
2150 | for (j = 0; a[j] && a[j] == b[j]; j++) | 2148 | for (j = 0; a[j] && a[j] == b[j]; j++) | |
2151 | continue; | 2149 | continue; | |
2152 | if (min > j) | 2150 | if (min > j) | |
2153 | min = j; | 2151 | min = j; | |
2154 | } | 2152 | } | |
2155 | if (min == 0 && *str) { | 2153 | if (min == 0 && *str) { | |
2156 | if ((list[0] = strdup(str)) == NULL) | 2154 | if ((list[0] = strdup(str)) == NULL) | |
2157 | goto out; | 2155 | goto out; | |
2158 | } else { | 2156 | } else { | |
2159 | if ((list[0] = el_malloc((min + 1) * sizeof(*list[0]))) == NULL) | 2157 | if ((list[0] = el_malloc((min + 1) * sizeof(*list[0]))) == NULL) | |
2160 | goto out; | 2158 | goto out; | |
2161 | (void)memcpy(list[0], list[1], min); | 2159 | (void)memcpy(list[0], list[1], min); | |
2162 | list[0][min] = '\0'; | 2160 | list[0][min] = '\0'; | |
2163 | } | 2161 | } | |
2164 | return list; | 2162 | return list; | |
2165 | 2163 | |||
2166 | out: | 2164 | out: | |
2167 | el_free(list); | 2165 | el_free(list); | |
2168 | return NULL; | 2166 | return NULL; | |
2169 | } | 2167 | } | |
2170 | 2168 | |||
2171 | char * | 2169 | char * | |
2172 | rl_filename_completion_function (const char *text, int state) | 2170 | rl_filename_completion_function (const char *text, int state) | |
2173 | { | 2171 | { | |
2174 | return fn_filename_completion_function(text, state); | 2172 | return fn_filename_completion_function(text, state); | |
2175 | } | 2173 | } | |
2176 | 2174 | |||
2177 | void | 2175 | void | |
2178 | rl_forced_update_display(void) | 2176 | rl_forced_update_display(void) | |
2179 | { | 2177 | { | |
2180 | el_set(e, EL_REFRESH); | 2178 | el_set(e, EL_REFRESH); | |
2181 | } | 2179 | } | |
2182 | 2180 | |||
2183 | int | 2181 | int | |
2184 | _rl_abort_internal(void) | 2182 | _rl_abort_internal(void) | |
2185 | { | 2183 | { | |
2186 | el_beep(e); | 2184 | el_beep(e); | |
2187 | longjmp(topbuf, 1); | 2185 | longjmp(topbuf, 1); | |
2188 | /*NOTREACHED*/ | 2186 | /*NOTREACHED*/ | |
2189 | } | 2187 | } | |
2190 | 2188 | |||
2191 | int | 2189 | int | |
2192 | _rl_qsort_string_compare(char **s1, char **s2) | 2190 | _rl_qsort_string_compare(char **s1, char **s2) | |
2193 | { | 2191 | { | |
2194 | return strcoll(*s1, *s2); | 2192 | return strcoll(*s1, *s2); | |
2195 | } | 2193 | } | |
2196 | 2194 | |||
2197 | HISTORY_STATE * | 2195 | HISTORY_STATE * | |
2198 | history_get_history_state(void) | 2196 | history_get_history_state(void) | |
2199 | { | 2197 | { | |
2200 | HISTORY_STATE *hs; | 2198 | HISTORY_STATE *hs; | |
2201 | 2199 | |||
2202 | if ((hs = el_malloc(sizeof(*hs))) == NULL) | 2200 | if ((hs = el_malloc(sizeof(*hs))) == NULL) | |
2203 | return NULL; | 2201 | return NULL; | |
2204 | hs->length = history_length; | 2202 | hs->length = history_length; | |
2205 | return hs; | 2203 | return hs; | |
2206 | } | 2204 | } | |
2207 | 2205 | |||
2208 | int | 2206 | int | |
2209 | /*ARGSUSED*/ | 2207 | /*ARGSUSED*/ | |
2210 | rl_kill_text(int from, int to) | 2208 | rl_kill_text(int from __attribute__((__unused__)), | |
2209 | int to __attribute__((__unused__))) | |||
2211 | { | 2210 | { | |
2212 | return 0; | 2211 | return 0; | |
2213 | } | 2212 | } | |
2214 | 2213 | |||
2215 | Keymap | 2214 | Keymap | |
2216 | rl_make_bare_keymap(void) | 2215 | rl_make_bare_keymap(void) | |
2217 | { | 2216 | { | |
2218 | return NULL; | 2217 | return NULL; | |
2219 | } | 2218 | } | |
2220 | 2219 | |||
2221 | Keymap | 2220 | Keymap | |
2222 | rl_get_keymap(void) | 2221 | rl_get_keymap(void) | |
2223 | { | 2222 | { | |
2224 | return NULL; | 2223 | return NULL; | |
2225 | } | 2224 | } | |
2226 | 2225 | |||
2227 | void | 2226 | void | |
2228 | /*ARGSUSED*/ | 2227 | /*ARGSUSED*/ | |
2229 | rl_set_keymap(Keymap k) | 2228 | rl_set_keymap(Keymap k __attribute__((__unused__))) | |
2230 | { | 2229 | { | |
2231 | } | 2230 | } | |
2232 | 2231 | |||
2233 | int | 2232 | int | |
2234 | /*ARGSUSED*/ | 2233 | /*ARGSUSED*/ | |
2235 | rl_generic_bind(int type, const char * keyseq, const char * data, Keymap k) | 2234 | rl_generic_bind(int type __attribute__((__unused__)), | |
2235 | const char * keyseq __attribute__((__unused__)), | |||
2236 | const char * data __attribute__((__unused__)), | |||
2237 | Keymap k __attribute__((__unused__))) | |||
2236 | { | 2238 | { | |
2237 | return 0; | 2239 | return 0; | |
2238 | } | 2240 | } | |
2239 | 2241 | |||
2240 | int | 2242 | int | |
2241 | /*ARGSUSED*/ | 2243 | /*ARGSUSED*/ | |
2242 | rl_bind_key_in_map(int key, rl_command_func_t *fun, Keymap k) | 2244 | rl_bind_key_in_map(int key __attribute__((__unused__)), | |
2245 | rl_command_func_t *fun __attribute__((__unused__)), | |||
2246 | Keymap k __attribute__((__unused__))) | |||
2243 | { | 2247 | { | |
2244 | return 0; | 2248 | return 0; | |
2245 | } | 2249 | } | |
2246 | 2250 | |||
2247 | /* unsupported, but needed by python */ | 2251 | /* unsupported, but needed by python */ | |
2248 | void | 2252 | void | |
2249 | rl_cleanup_after_signal(void) | 2253 | rl_cleanup_after_signal(void) | |
2250 | { | 2254 | { | |
2251 | } | 2255 | } | |
2252 | 2256 | |||
2253 | int | 2257 | int | |
2254 | rl_on_new_line(void) | 2258 | rl_on_new_line(void) | |
2255 | { | 2259 | { | |
2256 | return 0; | 2260 | return 0; | |
2257 | } | 2261 | } |
--- src/lib/libedit/vi.c 2011/07/29 15:16:33 1.37
+++ src/lib/libedit/vi.c 2011/07/29 20:58:07 1.38
@@ -1,1161 +1,1161 @@ | @@ -1,1161 +1,1161 @@ | |||
1 | /* $NetBSD: vi.c,v 1.37 2011/07/29 15:16:33 christos Exp $ */ | 1 | /* $NetBSD: vi.c,v 1.38 2011/07/29 20:58:07 christos Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1992, 1993 | 4 | * Copyright (c) 1992, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Christos Zoulas of Cornell University. | 8 | * Christos Zoulas of Cornell University. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | #include "config.h" | 35 | #include "config.h" | |
36 | #include <stdlib.h> | 36 | #include <stdlib.h> | |
37 | #include <unistd.h> | 37 | #include <unistd.h> | |
38 | #include <limits.h> | 38 | #include <limits.h> | |
39 | #include <sys/wait.h> | 39 | #include <sys/wait.h> | |
40 | 40 | |||
41 | #if !defined(lint) && !defined(SCCSID) | 41 | #if !defined(lint) && !defined(SCCSID) | |
42 | #if 0 | 42 | #if 0 | |
43 | static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; | 43 | static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; | |
44 | #else | 44 | #else | |
45 | __RCSID("$NetBSD: vi.c,v 1.37 2011/07/29 15:16:33 christos Exp $"); | 45 | __RCSID("$NetBSD: vi.c,v 1.38 2011/07/29 20:58:07 christos Exp $"); | |
46 | #endif | 46 | #endif | |
47 | #endif /* not lint && not SCCSID */ | 47 | #endif /* not lint && not SCCSID */ | |
48 | 48 | |||
49 | /* | 49 | /* | |
50 | * vi.c: Vi mode commands. | 50 | * vi.c: Vi mode commands. | |
51 | */ | 51 | */ | |
52 | #include "el.h" | 52 | #include "el.h" | |
53 | 53 | |||
54 | private el_action_t cv_action(EditLine *, Int); | 54 | private el_action_t cv_action(EditLine *, Int); | |
55 | private el_action_t cv_paste(EditLine *, Int); | 55 | private el_action_t cv_paste(EditLine *, Int); | |
56 | 56 | |||
57 | /* cv_action(): | 57 | /* cv_action(): | |
58 | * Handle vi actions. | 58 | * Handle vi actions. | |
59 | */ | 59 | */ | |
60 | private el_action_t | 60 | private el_action_t | |
61 | cv_action(EditLine *el, Int c) | 61 | cv_action(EditLine *el, Int c) | |
62 | { | 62 | { | |
63 | 63 | |||
64 | if (el->el_chared.c_vcmd.action != NOP) { | 64 | if (el->el_chared.c_vcmd.action != NOP) { | |
65 | /* 'cc', 'dd' and (possibly) friends */ | 65 | /* 'cc', 'dd' and (possibly) friends */ | |
66 | if (c != el->el_chared.c_vcmd.action) | 66 | if (c != el->el_chared.c_vcmd.action) | |
67 | return CC_ERROR; | 67 | return CC_ERROR; | |
68 | 68 | |||
69 | if (!(c & YANK)) | 69 | if (!(c & YANK)) | |
70 | cv_undo(el); | 70 | cv_undo(el); | |
71 | cv_yank(el, el->el_line.buffer, | 71 | cv_yank(el, el->el_line.buffer, | |
72 | (int)(el->el_line.lastchar - el->el_line.buffer)); | 72 | (int)(el->el_line.lastchar - el->el_line.buffer)); | |
73 | el->el_chared.c_vcmd.action = NOP; | 73 | el->el_chared.c_vcmd.action = NOP; | |
74 | el->el_chared.c_vcmd.pos = 0; | 74 | el->el_chared.c_vcmd.pos = 0; | |
75 | if (!(c & YANK)) { | 75 | if (!(c & YANK)) { | |
76 | el->el_line.lastchar = el->el_line.buffer; | 76 | el->el_line.lastchar = el->el_line.buffer; | |
77 | el->el_line.cursor = el->el_line.buffer; | 77 | el->el_line.cursor = el->el_line.buffer; | |
78 | } | 78 | } | |
79 | if (c & INSERT) | 79 | if (c & INSERT) | |
80 | el->el_map.current = el->el_map.key; | 80 | el->el_map.current = el->el_map.key; | |
81 | 81 | |||
82 | return CC_REFRESH; | 82 | return CC_REFRESH; | |
83 | } | 83 | } | |
84 | el->el_chared.c_vcmd.pos = el->el_line.cursor; | 84 | el->el_chared.c_vcmd.pos = el->el_line.cursor; | |
85 | el->el_chared.c_vcmd.action = c; | 85 | el->el_chared.c_vcmd.action = c; | |
86 | return CC_ARGHACK; | 86 | return CC_ARGHACK; | |
87 | } | 87 | } | |
88 | 88 | |||
89 | /* cv_paste(): | 89 | /* cv_paste(): | |
90 | * Paste previous deletion before or after the cursor | 90 | * Paste previous deletion before or after the cursor | |
91 | */ | 91 | */ | |
92 | private el_action_t | 92 | private el_action_t | |
93 | cv_paste(EditLine *el, Int c) | 93 | cv_paste(EditLine *el, Int c) | |
94 | { | 94 | { | |
95 | c_kill_t *k = &el->el_chared.c_kill; | 95 | c_kill_t *k = &el->el_chared.c_kill; | |
96 | size_t len = (size_t)(k->last - k->buf); | 96 | size_t len = (size_t)(k->last - k->buf); | |
97 | 97 | |||
98 | if (k->buf == NULL || len == 0) | 98 | if (k->buf == NULL || len == 0) | |
99 | return CC_ERROR; | 99 | return CC_ERROR; | |
100 | #ifdef DEBUG_PASTE | 100 | #ifdef DEBUG_PASTE | |
101 | (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf); | 101 | (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf); | |
102 | #endif | 102 | #endif | |
103 | 103 | |||
104 | cv_undo(el); | 104 | cv_undo(el); | |
105 | 105 | |||
106 | if (!c && el->el_line.cursor < el->el_line.lastchar) | 106 | if (!c && el->el_line.cursor < el->el_line.lastchar) | |
107 | el->el_line.cursor++; | 107 | el->el_line.cursor++; | |
108 | 108 | |||
109 | c_insert(el, (int)len); | 109 | c_insert(el, (int)len); | |
110 | if (el->el_line.cursor + len > el->el_line.lastchar) | 110 | if (el->el_line.cursor + len > el->el_line.lastchar) | |
111 | return CC_ERROR; | 111 | return CC_ERROR; | |
112 | (void) memcpy(el->el_line.cursor, k->buf, len * | 112 | (void) memcpy(el->el_line.cursor, k->buf, len * | |
113 | sizeof(*el->el_line.cursor)); | 113 | sizeof(*el->el_line.cursor)); | |
114 | 114 | |||
115 | return CC_REFRESH; | 115 | return CC_REFRESH; | |
116 | } | 116 | } | |
117 | 117 | |||
118 | 118 | |||
119 | /* vi_paste_next(): | 119 | /* vi_paste_next(): | |
120 | * Vi paste previous deletion to the right of the cursor | 120 | * Vi paste previous deletion to the right of the cursor | |
121 | * [p] | 121 | * [p] | |
122 | */ | 122 | */ | |
123 | protected el_action_t | 123 | protected el_action_t | |
124 | /*ARGSUSED*/ | 124 | /*ARGSUSED*/ | |
125 | vi_paste_next(EditLine *el, Int c __attribute__((__unused__))) | 125 | vi_paste_next(EditLine *el, Int c __attribute__((__unused__))) | |
126 | { | 126 | { | |
127 | 127 | |||
128 | return cv_paste(el, 0); | 128 | return cv_paste(el, 0); | |
129 | } | 129 | } | |
130 | 130 | |||
131 | 131 | |||
132 | /* vi_paste_prev(): | 132 | /* vi_paste_prev(): | |
133 | * Vi paste previous deletion to the left of the cursor | 133 | * Vi paste previous deletion to the left of the cursor | |
134 | * [P] | 134 | * [P] | |
135 | */ | 135 | */ | |
136 | protected el_action_t | 136 | protected el_action_t | |
137 | /*ARGSUSED*/ | 137 | /*ARGSUSED*/ | |
138 | vi_paste_prev(EditLine *el, Int c __attribute__((__unused__))) | 138 | vi_paste_prev(EditLine *el, Int c __attribute__((__unused__))) | |
139 | { | 139 | { | |
140 | 140 | |||
141 | return cv_paste(el, 1); | 141 | return cv_paste(el, 1); | |
142 | } | 142 | } | |
143 | 143 | |||
144 | 144 | |||
145 | /* vi_prev_big_word(): | 145 | /* vi_prev_big_word(): | |
146 | * Vi move to the previous space delimited word | 146 | * Vi move to the previous space delimited word | |
147 | * [B] | 147 | * [B] | |
148 | */ | 148 | */ | |
149 | protected el_action_t | 149 | protected el_action_t | |
150 | /*ARGSUSED*/ | 150 | /*ARGSUSED*/ | |
151 | vi_prev_big_word(EditLine *el, Int c __attribute__((__unused__))) | 151 | vi_prev_big_word(EditLine *el, Int c __attribute__((__unused__))) | |
152 | { | 152 | { | |
153 | 153 | |||
154 | if (el->el_line.cursor == el->el_line.buffer) | 154 | if (el->el_line.cursor == el->el_line.buffer) | |
155 | return CC_ERROR; | 155 | return CC_ERROR; | |
156 | 156 | |||
157 | el->el_line.cursor = cv_prev_word(el->el_line.cursor, | 157 | el->el_line.cursor = cv_prev_word(el->el_line.cursor, | |
158 | el->el_line.buffer, | 158 | el->el_line.buffer, | |
159 | el->el_state.argument, | 159 | el->el_state.argument, | |
160 | cv__isWord); | 160 | cv__isWord); | |
161 | 161 | |||
162 | if (el->el_chared.c_vcmd.action != NOP) { | 162 | if (el->el_chared.c_vcmd.action != NOP) { | |
163 | cv_delfini(el); | 163 | cv_delfini(el); | |
164 | return CC_REFRESH; | 164 | return CC_REFRESH; | |
165 | } | 165 | } | |
166 | return CC_CURSOR; | 166 | return CC_CURSOR; | |
167 | } | 167 | } | |
168 | 168 | |||
169 | 169 | |||
170 | /* vi_prev_word(): | 170 | /* vi_prev_word(): | |
171 | * Vi move to the previous word | 171 | * Vi move to the previous word | |
172 | * [b] | 172 | * [b] | |
173 | */ | 173 | */ | |
174 | protected el_action_t | 174 | protected el_action_t | |
175 | /*ARGSUSED*/ | 175 | /*ARGSUSED*/ | |
176 | vi_prev_word(EditLine *el, Int c __attribute__((__unused__))) | 176 | vi_prev_word(EditLine *el, Int c __attribute__((__unused__))) | |
177 | { | 177 | { | |
178 | 178 | |||
179 | if (el->el_line.cursor == el->el_line.buffer) | 179 | if (el->el_line.cursor == el->el_line.buffer) | |
180 | return CC_ERROR; | 180 | return CC_ERROR; | |
181 | 181 | |||
182 | el->el_line.cursor = cv_prev_word(el->el_line.cursor, | 182 | el->el_line.cursor = cv_prev_word(el->el_line.cursor, | |
183 | el->el_line.buffer, | 183 | el->el_line.buffer, | |
184 | el->el_state.argument, | 184 | el->el_state.argument, | |
185 | cv__isword); | 185 | cv__isword); | |
186 | 186 | |||
187 | if (el->el_chared.c_vcmd.action != NOP) { | 187 | if (el->el_chared.c_vcmd.action != NOP) { | |
188 | cv_delfini(el); | 188 | cv_delfini(el); | |
189 | return CC_REFRESH; | 189 | return CC_REFRESH; | |
190 | } | 190 | } | |
191 | return CC_CURSOR; | 191 | return CC_CURSOR; | |
192 | } | 192 | } | |
193 | 193 | |||
194 | 194 | |||
195 | /* vi_next_big_word(): | 195 | /* vi_next_big_word(): | |
196 | * Vi move to the next space delimited word | 196 | * Vi move to the next space delimited word | |
197 | * [W] | 197 | * [W] | |
198 | */ | 198 | */ | |
199 | protected el_action_t | 199 | protected el_action_t | |
200 | /*ARGSUSED*/ | 200 | /*ARGSUSED*/ | |
201 | vi_next_big_word(EditLine *el, Int c __attribute__((__unused__))) | 201 | vi_next_big_word(EditLine *el, Int c __attribute__((__unused__))) | |
202 | { | 202 | { | |
203 | 203 | |||
204 | if (el->el_line.cursor >= el->el_line.lastchar - 1) | 204 | if (el->el_line.cursor >= el->el_line.lastchar - 1) | |
205 | return CC_ERROR; | 205 | return CC_ERROR; | |
206 | 206 | |||
207 | el->el_line.cursor = cv_next_word(el, el->el_line.cursor, | 207 | el->el_line.cursor = cv_next_word(el, el->el_line.cursor, | |
208 | el->el_line.lastchar, el->el_state.argument, cv__isWord); | 208 | el->el_line.lastchar, el->el_state.argument, cv__isWord); | |
209 | 209 | |||
210 | if (el->el_map.type == MAP_VI) | 210 | if (el->el_map.type == MAP_VI) | |
211 | if (el->el_chared.c_vcmd.action != NOP) { | 211 | if (el->el_chared.c_vcmd.action != NOP) { | |
212 | cv_delfini(el); | 212 | cv_delfini(el); | |
213 | return CC_REFRESH; | 213 | return CC_REFRESH; | |
214 | } | 214 | } | |
215 | return CC_CURSOR; | 215 | return CC_CURSOR; | |
216 | } | 216 | } | |
217 | 217 | |||
218 | 218 | |||
219 | /* vi_next_word(): | 219 | /* vi_next_word(): | |
220 | * Vi move to the next word | 220 | * Vi move to the next word | |
221 | * [w] | 221 | * [w] | |
222 | */ | 222 | */ | |
223 | protected el_action_t | 223 | protected el_action_t | |
224 | /*ARGSUSED*/ | 224 | /*ARGSUSED*/ | |
225 | vi_next_word(EditLine *el, Int c __attribute__((__unused__))) | 225 | vi_next_word(EditLine *el, Int c __attribute__((__unused__))) | |
226 | { | 226 | { | |
227 | 227 | |||
228 | if (el->el_line.cursor >= el->el_line.lastchar - 1) | 228 | if (el->el_line.cursor >= el->el_line.lastchar - 1) | |
229 | return CC_ERROR; | 229 | return CC_ERROR; | |
230 | 230 | |||
231 | el->el_line.cursor = cv_next_word(el, el->el_line.cursor, | 231 | el->el_line.cursor = cv_next_word(el, el->el_line.cursor, | |
232 | el->el_line.lastchar, el->el_state.argument, cv__isword); | 232 | el->el_line.lastchar, el->el_state.argument, cv__isword); | |
233 | 233 | |||
234 | if (el->el_map.type == MAP_VI) | 234 | if (el->el_map.type == MAP_VI) | |
235 | if (el->el_chared.c_vcmd.action != NOP) { | 235 | if (el->el_chared.c_vcmd.action != NOP) { | |
236 | cv_delfini(el); | 236 | cv_delfini(el); | |
237 | return CC_REFRESH; | 237 | return CC_REFRESH; | |
238 | } | 238 | } | |
239 | return CC_CURSOR; | 239 | return CC_CURSOR; | |
240 | } | 240 | } | |
241 | 241 | |||
242 | 242 | |||
243 | /* vi_change_case(): | 243 | /* vi_change_case(): | |
244 | * Vi change case of character under the cursor and advance one character | 244 | * Vi change case of character under the cursor and advance one character | |
245 | * [~] | 245 | * [~] | |
246 | */ | 246 | */ | |
247 | protected el_action_t | 247 | protected el_action_t | |
248 | vi_change_case(EditLine *el, Int c) | 248 | vi_change_case(EditLine *el, Int c) | |
249 | { | 249 | { | |
250 | int i; | 250 | int i; | |
251 | 251 | |||
252 | if (el->el_line.cursor >= el->el_line.lastchar) | 252 | if (el->el_line.cursor >= el->el_line.lastchar) | |
253 | return CC_ERROR; | 253 | return CC_ERROR; | |
254 | cv_undo(el); | 254 | cv_undo(el); | |
255 | for (i = 0; i < el->el_state.argument; i++) { | 255 | for (i = 0; i < el->el_state.argument; i++) { | |
256 | 256 | |||
257 | c = *el->el_line.cursor; | 257 | c = *el->el_line.cursor; | |
258 | if (Isupper(c)) | 258 | if (Isupper(c)) | |
259 | *el->el_line.cursor = Tolower(c); | 259 | *el->el_line.cursor = Tolower(c); | |
260 | else if (Islower(c)) | 260 | else if (Islower(c)) | |
261 | *el->el_line.cursor = Toupper(c); | 261 | *el->el_line.cursor = Toupper(c); | |
262 | 262 | |||
263 | if (++el->el_line.cursor >= el->el_line.lastchar) { | 263 | if (++el->el_line.cursor >= el->el_line.lastchar) { | |
264 | el->el_line.cursor--; | 264 | el->el_line.cursor--; | |
265 | re_fastaddc(el); | 265 | re_fastaddc(el); | |
266 | break; | 266 | break; | |
267 | } | 267 | } | |
268 | re_fastaddc(el); | 268 | re_fastaddc(el); | |
269 | } | 269 | } | |
270 | return CC_NORM; | 270 | return CC_NORM; | |
271 | } | 271 | } | |
272 | 272 | |||
273 | 273 | |||
274 | /* vi_change_meta(): | 274 | /* vi_change_meta(): | |
275 | * Vi change prefix command | 275 | * Vi change prefix command | |
276 | * [c] | 276 | * [c] | |
277 | */ | 277 | */ | |
278 | protected el_action_t | 278 | protected el_action_t | |
279 | /*ARGSUSED*/ | 279 | /*ARGSUSED*/ | |
280 | vi_change_meta(EditLine *el, Int c __attribute__((__unused__))) | 280 | vi_change_meta(EditLine *el, Int c __attribute__((__unused__))) | |
281 | { | 281 | { | |
282 | 282 | |||
283 | /* | 283 | /* | |
284 | * Delete with insert == change: first we delete and then we leave in | 284 | * Delete with insert == change: first we delete and then we leave in | |
285 | * insert mode. | 285 | * insert mode. | |
286 | */ | 286 | */ | |
287 | return cv_action(el, DELETE | INSERT); | 287 | return cv_action(el, DELETE | INSERT); | |
288 | } | 288 | } | |
289 | 289 | |||
290 | 290 | |||
291 | /* vi_insert_at_bol(): | 291 | /* vi_insert_at_bol(): | |
292 | * Vi enter insert mode at the beginning of line | 292 | * Vi enter insert mode at the beginning of line | |
293 | * [I] | 293 | * [I] | |
294 | */ | 294 | */ | |
295 | protected el_action_t | 295 | protected el_action_t | |
296 | /*ARGSUSED*/ | 296 | /*ARGSUSED*/ | |
297 | vi_insert_at_bol(EditLine *el, Int c __attribute__((__unused__))) | 297 | vi_insert_at_bol(EditLine *el, Int c __attribute__((__unused__))) | |
298 | { | 298 | { | |
299 | 299 | |||
300 | el->el_line.cursor = el->el_line.buffer; | 300 | el->el_line.cursor = el->el_line.buffer; | |
301 | cv_undo(el); | 301 | cv_undo(el); | |
302 | el->el_map.current = el->el_map.key; | 302 | el->el_map.current = el->el_map.key; | |
303 | return CC_CURSOR; | 303 | return CC_CURSOR; | |
304 | } | 304 | } | |
305 | 305 | |||
306 | 306 | |||
307 | /* vi_replace_char(): | 307 | /* vi_replace_char(): | |
308 | * Vi replace character under the cursor with the next character typed | 308 | * Vi replace character under the cursor with the next character typed | |
309 | * [r] | 309 | * [r] | |
310 | */ | 310 | */ | |
311 | protected el_action_t | 311 | protected el_action_t | |
312 | /*ARGSUSED*/ | 312 | /*ARGSUSED*/ | |
313 | vi_replace_char(EditLine *el, Int c __attribute__((__unused__))) | 313 | vi_replace_char(EditLine *el, Int c __attribute__((__unused__))) | |
314 | { | 314 | { | |
315 | 315 | |||
316 | if (el->el_line.cursor >= el->el_line.lastchar) | 316 | if (el->el_line.cursor >= el->el_line.lastchar) | |
317 | return CC_ERROR; | 317 | return CC_ERROR; | |
318 | 318 | |||
319 | el->el_map.current = el->el_map.key; | 319 | el->el_map.current = el->el_map.key; | |
320 | el->el_state.inputmode = MODE_REPLACE_1; | 320 | el->el_state.inputmode = MODE_REPLACE_1; | |
321 | cv_undo(el); | 321 | cv_undo(el); | |
322 | return CC_ARGHACK; | 322 | return CC_ARGHACK; | |
323 | } | 323 | } | |
324 | 324 | |||
325 | 325 | |||
326 | /* vi_replace_mode(): | 326 | /* vi_replace_mode(): | |
327 | * Vi enter replace mode | 327 | * Vi enter replace mode | |
328 | * [R] | 328 | * [R] | |
329 | */ | 329 | */ | |
330 | protected el_action_t | 330 | protected el_action_t | |
331 | /*ARGSUSED*/ | 331 | /*ARGSUSED*/ | |
332 | vi_replace_mode(EditLine *el, Int c __attribute__((__unused__))) | 332 | vi_replace_mode(EditLine *el, Int c __attribute__((__unused__))) | |
333 | { | 333 | { | |
334 | 334 | |||
335 | el->el_map.current = el->el_map.key; | 335 | el->el_map.current = el->el_map.key; | |
336 | el->el_state.inputmode = MODE_REPLACE; | 336 | el->el_state.inputmode = MODE_REPLACE; | |
337 | cv_undo(el); | 337 | cv_undo(el); | |
338 | return CC_NORM; | 338 | return CC_NORM; | |
339 | } | 339 | } | |
340 | 340 | |||
341 | 341 | |||
342 | /* vi_substitute_char(): | 342 | /* vi_substitute_char(): | |
343 | * Vi replace character under the cursor and enter insert mode | 343 | * Vi replace character under the cursor and enter insert mode | |
344 | * [s] | 344 | * [s] | |
345 | */ | 345 | */ | |
346 | protected el_action_t | 346 | protected el_action_t | |
347 | /*ARGSUSED*/ | 347 | /*ARGSUSED*/ | |
348 | vi_substitute_char(EditLine *el, Int c __attribute__((__unused__))) | 348 | vi_substitute_char(EditLine *el, Int c __attribute__((__unused__))) | |
349 | { | 349 | { | |
350 | 350 | |||
351 | c_delafter(el, el->el_state.argument); | 351 | c_delafter(el, el->el_state.argument); | |
352 | el->el_map.current = el->el_map.key; | 352 | el->el_map.current = el->el_map.key; | |
353 | return CC_REFRESH; | 353 | return CC_REFRESH; | |
354 | } | 354 | } | |
355 | 355 | |||
356 | 356 | |||
357 | /* vi_substitute_line(): | 357 | /* vi_substitute_line(): | |
358 | * Vi substitute entire line | 358 | * Vi substitute entire line | |
359 | * [S] | 359 | * [S] | |
360 | */ | 360 | */ | |
361 | protected el_action_t | 361 | protected el_action_t | |
362 | /*ARGSUSED*/ | 362 | /*ARGSUSED*/ | |
363 | vi_substitute_line(EditLine *el, Int c __attribute__((__unused__))) | 363 | vi_substitute_line(EditLine *el, Int c __attribute__((__unused__))) | |
364 | { | 364 | { | |
365 | 365 | |||
366 | cv_undo(el); | 366 | cv_undo(el); | |
367 | cv_yank(el, el->el_line.buffer, | 367 | cv_yank(el, el->el_line.buffer, | |
368 | (int)(el->el_line.lastchar - el->el_line.buffer)); | 368 | (int)(el->el_line.lastchar - el->el_line.buffer)); | |
369 | (void) em_kill_line(el, 0); | 369 | (void) em_kill_line(el, 0); | |
370 | el->el_map.current = el->el_map.key; | 370 | el->el_map.current = el->el_map.key; | |
371 | return CC_REFRESH; | 371 | return CC_REFRESH; | |
372 | } | 372 | } | |
373 | 373 | |||
374 | 374 | |||
375 | /* vi_change_to_eol(): | 375 | /* vi_change_to_eol(): | |
376 | * Vi change to end of line | 376 | * Vi change to end of line | |
377 | * [C] | 377 | * [C] | |
378 | */ | 378 | */ | |
379 | protected el_action_t | 379 | protected el_action_t | |
380 | /*ARGSUSED*/ | 380 | /*ARGSUSED*/ | |
381 | vi_change_to_eol(EditLine *el, Int c __attribute__((__unused__))) | 381 | vi_change_to_eol(EditLine *el, Int c __attribute__((__unused__))) | |
382 | { | 382 | { | |
383 | 383 | |||
384 | cv_undo(el); | 384 | cv_undo(el); | |
385 | cv_yank(el, el->el_line.cursor, | 385 | cv_yank(el, el->el_line.cursor, | |
386 | (int)(el->el_line.lastchar - el->el_line.cursor)); | 386 | (int)(el->el_line.lastchar - el->el_line.cursor)); | |
387 | (void) ed_kill_line(el, 0); | 387 | (void) ed_kill_line(el, 0); | |
388 | el->el_map.current = el->el_map.key; | 388 | el->el_map.current = el->el_map.key; | |
389 | return CC_REFRESH; | 389 | return CC_REFRESH; | |
390 | } | 390 | } | |
391 | 391 | |||
392 | 392 | |||
393 | /* vi_insert(): | 393 | /* vi_insert(): | |
394 | * Vi enter insert mode | 394 | * Vi enter insert mode | |
395 | * [i] | 395 | * [i] | |
396 | */ | 396 | */ | |
397 | protected el_action_t | 397 | protected el_action_t | |
398 | /*ARGSUSED*/ | 398 | /*ARGSUSED*/ | |
399 | vi_insert(EditLine *el, Int c __attribute__((__unused__))) | 399 | vi_insert(EditLine *el, Int c __attribute__((__unused__))) | |
400 | { | 400 | { | |
401 | 401 | |||
402 | el->el_map.current = el->el_map.key; | 402 | el->el_map.current = el->el_map.key; | |
403 | cv_undo(el); | 403 | cv_undo(el); | |
404 | return CC_NORM; | 404 | return CC_NORM; | |
405 | } | 405 | } | |
406 | 406 | |||
407 | 407 | |||
408 | /* vi_add(): | 408 | /* vi_add(): | |
409 | * Vi enter insert mode after the cursor | 409 | * Vi enter insert mode after the cursor | |
410 | * [a] | 410 | * [a] | |
411 | */ | 411 | */ | |
412 | protected el_action_t | 412 | protected el_action_t | |
413 | /*ARGSUSED*/ | 413 | /*ARGSUSED*/ | |
414 | vi_add(EditLine *el, Int c __attribute__((__unused__))) | 414 | vi_add(EditLine *el, Int c __attribute__((__unused__))) | |
415 | { | 415 | { | |
416 | int ret; | 416 | int ret; | |
417 | 417 | |||
418 | el->el_map.current = el->el_map.key; | 418 | el->el_map.current = el->el_map.key; | |
419 | if (el->el_line.cursor < el->el_line.lastchar) { | 419 | if (el->el_line.cursor < el->el_line.lastchar) { | |
420 | el->el_line.cursor++; | 420 | el->el_line.cursor++; | |
421 | if (el->el_line.cursor > el->el_line.lastchar) | 421 | if (el->el_line.cursor > el->el_line.lastchar) | |
422 | el->el_line.cursor = el->el_line.lastchar; | 422 | el->el_line.cursor = el->el_line.lastchar; | |
423 | ret = CC_CURSOR; | 423 | ret = CC_CURSOR; | |
424 | } else | 424 | } else | |
425 | ret = CC_NORM; | 425 | ret = CC_NORM; | |
426 | 426 | |||
427 | cv_undo(el); | 427 | cv_undo(el); | |
428 | 428 | |||
429 | return ret; | 429 | return ret; | |
430 | } | 430 | } | |
431 | 431 | |||
432 | 432 | |||
433 | /* vi_add_at_eol(): | 433 | /* vi_add_at_eol(): | |
434 | * Vi enter insert mode at end of line | 434 | * Vi enter insert mode at end of line | |
435 | * [A] | 435 | * [A] | |
436 | */ | 436 | */ | |
437 | protected el_action_t | 437 | protected el_action_t | |
438 | /*ARGSUSED*/ | 438 | /*ARGSUSED*/ | |
439 | vi_add_at_eol(EditLine *el, Int c __attribute__((__unused__))) | 439 | vi_add_at_eol(EditLine *el, Int c __attribute__((__unused__))) | |
440 | { | 440 | { | |
441 | 441 | |||
442 | el->el_map.current = el->el_map.key; | 442 | el->el_map.current = el->el_map.key; | |
443 | el->el_line.cursor = el->el_line.lastchar; | 443 | el->el_line.cursor = el->el_line.lastchar; | |
444 | cv_undo(el); | 444 | cv_undo(el); | |
445 | return CC_CURSOR; | 445 | return CC_CURSOR; | |
446 | } | 446 | } | |
447 | 447 | |||
448 | 448 | |||
449 | /* vi_delete_meta(): | 449 | /* vi_delete_meta(): | |
450 | * Vi delete prefix command | 450 | * Vi delete prefix command | |
451 | * [d] | 451 | * [d] | |
452 | */ | 452 | */ | |
453 | protected el_action_t | 453 | protected el_action_t | |
454 | /*ARGSUSED*/ | 454 | /*ARGSUSED*/ | |
455 | vi_delete_meta(EditLine *el, Int c __attribute__((__unused__))) | 455 | vi_delete_meta(EditLine *el, Int c __attribute__((__unused__))) | |
456 | { | 456 | { | |
457 | 457 | |||
458 | return cv_action(el, DELETE); | 458 | return cv_action(el, DELETE); | |
459 | } | 459 | } | |
460 | 460 | |||
461 | 461 | |||
462 | /* vi_end_big_word(): | 462 | /* vi_end_big_word(): | |
463 | * Vi move to the end of the current space delimited word | 463 | * Vi move to the end of the current space delimited word | |
464 | * [E] | 464 | * [E] | |
465 | */ | 465 | */ | |
466 | protected el_action_t | 466 | protected el_action_t | |
467 | /*ARGSUSED*/ | 467 | /*ARGSUSED*/ | |
468 | vi_end_big_word(EditLine *el, Int c) | 468 | vi_end_big_word(EditLine *el, Int c __attribute__((__unused__))) | |
469 | { | 469 | { | |
470 | 470 | |||
471 | if (el->el_line.cursor == el->el_line.lastchar) | 471 | if (el->el_line.cursor == el->el_line.lastchar) | |
472 | return CC_ERROR; | 472 | return CC_ERROR; | |
473 | 473 | |||
474 | el->el_line.cursor = cv__endword(el->el_line.cursor, | 474 | el->el_line.cursor = cv__endword(el->el_line.cursor, | |
475 | el->el_line.lastchar, el->el_state.argument, cv__isWord); | 475 | el->el_line.lastchar, el->el_state.argument, cv__isWord); | |
476 | 476 | |||
477 | if (el->el_chared.c_vcmd.action != NOP) { | 477 | if (el->el_chared.c_vcmd.action != NOP) { | |
478 | el->el_line.cursor++; | 478 | el->el_line.cursor++; | |
479 | cv_delfini(el); | 479 | cv_delfini(el); | |
480 | return CC_REFRESH; | 480 | return CC_REFRESH; | |
481 | } | 481 | } | |
482 | return CC_CURSOR; | 482 | return CC_CURSOR; | |
483 | } | 483 | } | |
484 | 484 | |||
485 | 485 | |||
486 | /* vi_end_word(): | 486 | /* vi_end_word(): | |
487 | * Vi move to the end of the current word | 487 | * Vi move to the end of the current word | |
488 | * [e] | 488 | * [e] | |
489 | */ | 489 | */ | |
490 | protected el_action_t | 490 | protected el_action_t | |
491 | /*ARGSUSED*/ | 491 | /*ARGSUSED*/ | |
492 | vi_end_word(EditLine *el, Int c __attribute__((__unused__))) | 492 | vi_end_word(EditLine *el, Int c __attribute__((__unused__))) | |
493 | { | 493 | { | |
494 | 494 | |||
495 | if (el->el_line.cursor == el->el_line.lastchar) | 495 | if (el->el_line.cursor == el->el_line.lastchar) | |
496 | return CC_ERROR; | 496 | return CC_ERROR; | |
497 | 497 | |||
498 | el->el_line.cursor = cv__endword(el->el_line.cursor, | 498 | el->el_line.cursor = cv__endword(el->el_line.cursor, | |
499 | el->el_line.lastchar, el->el_state.argument, cv__isword); | 499 | el->el_line.lastchar, el->el_state.argument, cv__isword); | |
500 | 500 | |||
501 | if (el->el_chared.c_vcmd.action != NOP) { | 501 | if (el->el_chared.c_vcmd.action != NOP) { | |
502 | el->el_line.cursor++; | 502 | el->el_line.cursor++; | |
503 | cv_delfini(el); | 503 | cv_delfini(el); | |
504 | return CC_REFRESH; | 504 | return CC_REFRESH; | |
505 | } | 505 | } | |
506 | return CC_CURSOR; | 506 | return CC_CURSOR; | |
507 | } | 507 | } | |
508 | 508 | |||
509 | 509 | |||
510 | /* vi_undo(): | 510 | /* vi_undo(): | |
511 | * Vi undo last change | 511 | * Vi undo last change | |
512 | * [u] | 512 | * [u] | |
513 | */ | 513 | */ | |
514 | protected el_action_t | 514 | protected el_action_t | |
515 | /*ARGSUSED*/ | 515 | /*ARGSUSED*/ | |
516 | vi_undo(EditLine *el, Int c __attribute__((__unused__))) | 516 | vi_undo(EditLine *el, Int c __attribute__((__unused__))) | |
517 | { | 517 | { | |
518 | c_undo_t un = el->el_chared.c_undo; | 518 | c_undo_t un = el->el_chared.c_undo; | |
519 | 519 | |||
520 | if (un.len == -1) | 520 | if (un.len == -1) | |
521 | return CC_ERROR; | 521 | return CC_ERROR; | |
522 | 522 | |||
523 | /* switch line buffer and undo buffer */ | 523 | /* switch line buffer and undo buffer */ | |
524 | el->el_chared.c_undo.buf = el->el_line.buffer; | 524 | el->el_chared.c_undo.buf = el->el_line.buffer; | |
525 | el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer; | 525 | el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer; | |
526 | el->el_chared.c_undo.cursor = | 526 | el->el_chared.c_undo.cursor = | |
527 | (int)(el->el_line.cursor - el->el_line.buffer); | 527 | (int)(el->el_line.cursor - el->el_line.buffer); | |
528 | el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); | 528 | el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); | |
529 | el->el_line.buffer = un.buf; | 529 | el->el_line.buffer = un.buf; | |
530 | el->el_line.cursor = un.buf + un.cursor; | 530 | el->el_line.cursor = un.buf + un.cursor; | |
531 | el->el_line.lastchar = un.buf + un.len; | 531 | el->el_line.lastchar = un.buf + un.len; | |
532 | 532 | |||
533 | return CC_REFRESH; | 533 | return CC_REFRESH; | |
534 | } | 534 | } | |
535 | 535 | |||
536 | 536 | |||
537 | /* vi_command_mode(): | 537 | /* vi_command_mode(): | |
538 | * Vi enter command mode (use alternative key bindings) | 538 | * Vi enter command mode (use alternative key bindings) | |
539 | * [<ESC>] | 539 | * [<ESC>] | |
540 | */ | 540 | */ | |
541 | protected el_action_t | 541 | protected el_action_t | |
542 | /*ARGSUSED*/ | 542 | /*ARGSUSED*/ | |
543 | vi_command_mode(EditLine *el, Int c __attribute__((__unused__))) | 543 | vi_command_mode(EditLine *el, Int c __attribute__((__unused__))) | |
544 | { | 544 | { | |
545 | 545 | |||
546 | /* [Esc] cancels pending action */ | 546 | /* [Esc] cancels pending action */ | |
547 | el->el_chared.c_vcmd.action = NOP; | 547 | el->el_chared.c_vcmd.action = NOP; | |
548 | el->el_chared.c_vcmd.pos = 0; | 548 | el->el_chared.c_vcmd.pos = 0; | |
549 | 549 | |||
550 | el->el_state.doingarg = 0; | 550 | el->el_state.doingarg = 0; | |
551 | 551 | |||
552 | el->el_state.inputmode = MODE_INSERT; | 552 | el->el_state.inputmode = MODE_INSERT; | |
553 | el->el_map.current = el->el_map.alt; | 553 | el->el_map.current = el->el_map.alt; | |
554 | #ifdef VI_MOVE | 554 | #ifdef VI_MOVE | |
555 | if (el->el_line.cursor > el->el_line.buffer) | 555 | if (el->el_line.cursor > el->el_line.buffer) | |
556 | el->el_line.cursor--; | 556 | el->el_line.cursor--; | |
557 | #endif | 557 | #endif | |
558 | return CC_CURSOR; | 558 | return CC_CURSOR; | |
559 | } | 559 | } | |
560 | 560 | |||
561 | 561 | |||
562 | /* vi_zero(): | 562 | /* vi_zero(): | |
563 | * Vi move to the beginning of line | 563 | * Vi move to the beginning of line | |
564 | * [0] | 564 | * [0] | |
565 | */ | 565 | */ | |
566 | protected el_action_t | 566 | protected el_action_t | |
567 | vi_zero(EditLine *el, Int c) | 567 | vi_zero(EditLine *el, Int c) | |
568 | { | 568 | { | |
569 | 569 | |||
570 | if (el->el_state.doingarg) | 570 | if (el->el_state.doingarg) | |
571 | return ed_argument_digit(el, c); | 571 | return ed_argument_digit(el, c); | |
572 | 572 | |||
573 | el->el_line.cursor = el->el_line.buffer; | 573 | el->el_line.cursor = el->el_line.buffer; | |
574 | if (el->el_chared.c_vcmd.action != NOP) { | 574 | if (el->el_chared.c_vcmd.action != NOP) { | |
575 | cv_delfini(el); | 575 | cv_delfini(el); | |
576 | return CC_REFRESH; | 576 | return CC_REFRESH; | |
577 | } | 577 | } | |
578 | return CC_CURSOR; | 578 | return CC_CURSOR; | |
579 | } | 579 | } | |
580 | 580 | |||
581 | 581 | |||
582 | /* vi_delete_prev_char(): | 582 | /* vi_delete_prev_char(): | |
583 | * Vi move to previous character (backspace) | 583 | * Vi move to previous character (backspace) | |
584 | * [^H] in insert mode only | 584 | * [^H] in insert mode only | |
585 | */ | 585 | */ | |
586 | protected el_action_t | 586 | protected el_action_t | |
587 | /*ARGSUSED*/ | 587 | /*ARGSUSED*/ | |
588 | vi_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) | 588 | vi_delete_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
589 | { | 589 | { | |
590 | 590 | |||
591 | if (el->el_line.cursor <= el->el_line.buffer) | 591 | if (el->el_line.cursor <= el->el_line.buffer) | |
592 | return CC_ERROR; | 592 | return CC_ERROR; | |
593 | 593 | |||
594 | c_delbefore1(el); | 594 | c_delbefore1(el); | |
595 | el->el_line.cursor--; | 595 | el->el_line.cursor--; | |
596 | return CC_REFRESH; | 596 | return CC_REFRESH; | |
597 | } | 597 | } | |
598 | 598 | |||
599 | 599 | |||
600 | /* vi_list_or_eof(): | 600 | /* vi_list_or_eof(): | |
601 | * Vi list choices for completion or indicate end of file if empty line | 601 | * Vi list choices for completion or indicate end of file if empty line | |
602 | * [^D] | 602 | * [^D] | |
603 | */ | 603 | */ | |
604 | protected el_action_t | 604 | protected el_action_t | |
605 | /*ARGSUSED*/ | 605 | /*ARGSUSED*/ | |
606 | vi_list_or_eof(EditLine *el, Int c) | 606 | vi_list_or_eof(EditLine *el, Int c) | |
607 | { | 607 | { | |
608 | 608 | |||
609 | if (el->el_line.cursor == el->el_line.lastchar) { | 609 | if (el->el_line.cursor == el->el_line.lastchar) { | |
610 | if (el->el_line.cursor == el->el_line.buffer) { | 610 | if (el->el_line.cursor == el->el_line.buffer) { | |
611 | terminal_writec(el, c); /* then do a EOF */ | 611 | terminal_writec(el, c); /* then do a EOF */ | |
612 | return CC_EOF; | 612 | return CC_EOF; | |
613 | } else { | 613 | } else { | |
614 | /* | 614 | /* | |
615 | * Here we could list completions, but it is an | 615 | * Here we could list completions, but it is an | |
616 | * error right now | 616 | * error right now | |
617 | */ | 617 | */ | |
618 | terminal_beep(el); | 618 | terminal_beep(el); | |
619 | return CC_ERROR; | 619 | return CC_ERROR; | |
620 | } | 620 | } | |
621 | } else { | 621 | } else { | |
622 | #ifdef notyet | 622 | #ifdef notyet | |
623 | re_goto_bottom(el); | 623 | re_goto_bottom(el); | |
624 | *el->el_line.lastchar = '\0'; /* just in case */ | 624 | *el->el_line.lastchar = '\0'; /* just in case */ | |
625 | return CC_LIST_CHOICES; | 625 | return CC_LIST_CHOICES; | |
626 | #else | 626 | #else | |
627 | /* | 627 | /* | |
628 | * Just complain for now. | 628 | * Just complain for now. | |
629 | */ | 629 | */ | |
630 | terminal_beep(el); | 630 | terminal_beep(el); | |
631 | return CC_ERROR; | 631 | return CC_ERROR; | |
632 | #endif | 632 | #endif | |
633 | } | 633 | } | |
634 | } | 634 | } | |
635 | 635 | |||
636 | 636 | |||
637 | /* vi_kill_line_prev(): | 637 | /* vi_kill_line_prev(): | |
638 | * Vi cut from beginning of line to cursor | 638 | * Vi cut from beginning of line to cursor | |
639 | * [^U] | 639 | * [^U] | |
640 | */ | 640 | */ | |
641 | protected el_action_t | 641 | protected el_action_t | |
642 | /*ARGSUSED*/ | 642 | /*ARGSUSED*/ | |
643 | vi_kill_line_prev(EditLine *el, Int c __attribute__((__unused__))) | 643 | vi_kill_line_prev(EditLine *el, Int c __attribute__((__unused__))) | |
644 | { | 644 | { | |
645 | Char *kp, *cp; | 645 | Char *kp, *cp; | |
646 | 646 | |||
647 | cp = el->el_line.buffer; | 647 | cp = el->el_line.buffer; | |
648 | kp = el->el_chared.c_kill.buf; | 648 | kp = el->el_chared.c_kill.buf; | |
649 | while (cp < el->el_line.cursor) | 649 | while (cp < el->el_line.cursor) | |
650 | *kp++ = *cp++; /* copy it */ | 650 | *kp++ = *cp++; /* copy it */ | |
651 | el->el_chared.c_kill.last = kp; | 651 | el->el_chared.c_kill.last = kp; | |
652 | c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer)); | 652 | c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer)); | |
653 | el->el_line.cursor = el->el_line.buffer; /* zap! */ | 653 | el->el_line.cursor = el->el_line.buffer; /* zap! */ | |
654 | return CC_REFRESH; | 654 | return CC_REFRESH; | |
655 | } | 655 | } | |
656 | 656 | |||
657 | 657 | |||
658 | /* vi_search_prev(): | 658 | /* vi_search_prev(): | |
659 | * Vi search history previous | 659 | * Vi search history previous | |
660 | * [?] | 660 | * [?] | |
661 | */ | 661 | */ | |
662 | protected el_action_t | 662 | protected el_action_t | |
663 | /*ARGSUSED*/ | 663 | /*ARGSUSED*/ | |
664 | vi_search_prev(EditLine *el, Int c __attribute__((__unused__))) | 664 | vi_search_prev(EditLine *el, Int c __attribute__((__unused__))) | |
665 | { | 665 | { | |
666 | 666 | |||
667 | return cv_search(el, ED_SEARCH_PREV_HISTORY); | 667 | return cv_search(el, ED_SEARCH_PREV_HISTORY); | |
668 | } | 668 | } | |
669 | 669 | |||
670 | 670 | |||
671 | /* vi_search_next(): | 671 | /* vi_search_next(): | |
672 | * Vi search history next | 672 | * Vi search history next | |
673 | * [/] | 673 | * [/] | |
674 | */ | 674 | */ | |
675 | protected el_action_t | 675 | protected el_action_t | |
676 | /*ARGSUSED*/ | 676 | /*ARGSUSED*/ | |
677 | vi_search_next(EditLine *el, Int c __attribute__((__unused__))) | 677 | vi_search_next(EditLine *el, Int c __attribute__((__unused__))) | |
678 | { | 678 | { | |
679 | 679 | |||
680 | return cv_search(el, ED_SEARCH_NEXT_HISTORY); | 680 | return cv_search(el, ED_SEARCH_NEXT_HISTORY); | |
681 | } | 681 | } | |
682 | 682 | |||
683 | 683 | |||
684 | /* vi_repeat_search_next(): | 684 | /* vi_repeat_search_next(): | |
685 | * Vi repeat current search in the same search direction | 685 | * Vi repeat current search in the same search direction | |
686 | * [n] | 686 | * [n] | |
687 | */ | 687 | */ | |
688 | protected el_action_t | 688 | protected el_action_t | |
689 | /*ARGSUSED*/ | 689 | /*ARGSUSED*/ | |
690 | vi_repeat_search_next(EditLine *el, Int c __attribute__((__unused__))) | 690 | vi_repeat_search_next(EditLine *el, Int c __attribute__((__unused__))) | |
691 | { | 691 | { | |
692 | 692 | |||
693 | if (el->el_search.patlen == 0) | 693 | if (el->el_search.patlen == 0) | |
694 | return CC_ERROR; | 694 | return CC_ERROR; | |
695 | else | 695 | else | |
696 | return cv_repeat_srch(el, el->el_search.patdir); | 696 | return cv_repeat_srch(el, el->el_search.patdir); | |
697 | } | 697 | } | |
698 | 698 | |||
699 | 699 | |||
700 | /* vi_repeat_search_prev(): | 700 | /* vi_repeat_search_prev(): | |
701 | * Vi repeat current search in the opposite search direction | 701 | * Vi repeat current search in the opposite search direction | |
702 | * [N] | 702 | * [N] | |
703 | */ | 703 | */ | |
704 | /*ARGSUSED*/ | 704 | /*ARGSUSED*/ | |
705 | protected el_action_t | 705 | protected el_action_t | |
706 | vi_repeat_search_prev(EditLine *el, Int c __attribute__((__unused__))) | 706 | vi_repeat_search_prev(EditLine *el, Int c __attribute__((__unused__))) | |
707 | { | 707 | { | |
708 | 708 | |||
709 | if (el->el_search.patlen == 0) | 709 | if (el->el_search.patlen == 0) | |
710 | return CC_ERROR; | 710 | return CC_ERROR; | |
711 | else | 711 | else | |
712 | return (cv_repeat_srch(el, | 712 | return (cv_repeat_srch(el, | |
713 | el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? | 713 | el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? | |
714 | ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY)); | 714 | ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY)); | |
715 | } | 715 | } | |
716 | 716 | |||
717 | 717 | |||
718 | /* vi_next_char(): | 718 | /* vi_next_char(): | |
719 | * Vi move to the character specified next | 719 | * Vi move to the character specified next | |
720 | * [f] | 720 | * [f] | |
721 | */ | 721 | */ | |
722 | protected el_action_t | 722 | protected el_action_t | |
723 | /*ARGSUSED*/ | 723 | /*ARGSUSED*/ | |
724 | vi_next_char(EditLine *el, Int c __attribute__((__unused__))) | 724 | vi_next_char(EditLine *el, Int c __attribute__((__unused__))) | |
725 | { | 725 | { | |
726 | return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); | 726 | return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); | |
727 | } | 727 | } | |
728 | 728 | |||
729 | 729 | |||
730 | /* vi_prev_char(): | 730 | /* vi_prev_char(): | |
731 | * Vi move to the character specified previous | 731 | * Vi move to the character specified previous | |
732 | * [F] | 732 | * [F] | |
733 | */ | 733 | */ | |
734 | protected el_action_t | 734 | protected el_action_t | |
735 | /*ARGSUSED*/ | 735 | /*ARGSUSED*/ | |
736 | vi_prev_char(EditLine *el, Int c __attribute__((__unused__))) | 736 | vi_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
737 | { | 737 | { | |
738 | return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); | 738 | return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); | |
739 | } | 739 | } | |
740 | 740 | |||
741 | 741 | |||
742 | /* vi_to_next_char(): | 742 | /* vi_to_next_char(): | |
743 | * Vi move up to the character specified next | 743 | * Vi move up to the character specified next | |
744 | * [t] | 744 | * [t] | |
745 | */ | 745 | */ | |
746 | protected el_action_t | 746 | protected el_action_t | |
747 | /*ARGSUSED*/ | 747 | /*ARGSUSED*/ | |
748 | vi_to_next_char(EditLine *el, Int c __attribute__((__unused__))) | 748 | vi_to_next_char(EditLine *el, Int c __attribute__((__unused__))) | |
749 | { | 749 | { | |
750 | return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); | 750 | return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); | |
751 | } | 751 | } | |
752 | 752 | |||
753 | 753 | |||
754 | /* vi_to_prev_char(): | 754 | /* vi_to_prev_char(): | |
755 | * Vi move up to the character specified previous | 755 | * Vi move up to the character specified previous | |
756 | * [T] | 756 | * [T] | |
757 | */ | 757 | */ | |
758 | protected el_action_t | 758 | protected el_action_t | |
759 | /*ARGSUSED*/ | 759 | /*ARGSUSED*/ | |
760 | vi_to_prev_char(EditLine *el, Int c __attribute__((__unused__))) | 760 | vi_to_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
761 | { | 761 | { | |
762 | return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); | 762 | return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); | |
763 | } | 763 | } | |
764 | 764 | |||
765 | 765 | |||
766 | /* vi_repeat_next_char(): | 766 | /* vi_repeat_next_char(): | |
767 | * Vi repeat current character search in the same search direction | 767 | * Vi repeat current character search in the same search direction | |
768 | * [;] | 768 | * [;] | |
769 | */ | 769 | */ | |
770 | protected el_action_t | 770 | protected el_action_t | |
771 | /*ARGSUSED*/ | 771 | /*ARGSUSED*/ | |
772 | vi_repeat_next_char(EditLine *el, Int c __attribute__((__unused__))) | 772 | vi_repeat_next_char(EditLine *el, Int c __attribute__((__unused__))) | |
773 | { | 773 | { | |
774 | 774 | |||
775 | return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, | 775 | return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, | |
776 | el->el_state.argument, el->el_search.chatflg); | 776 | el->el_state.argument, el->el_search.chatflg); | |
777 | } | 777 | } | |
778 | 778 | |||
779 | 779 | |||
780 | /* vi_repeat_prev_char(): | 780 | /* vi_repeat_prev_char(): | |
781 | * Vi repeat current character search in the opposite search direction | 781 | * Vi repeat current character search in the opposite search direction | |
782 | * [,] | 782 | * [,] | |
783 | */ | 783 | */ | |
784 | protected el_action_t | 784 | protected el_action_t | |
785 | /*ARGSUSED*/ | 785 | /*ARGSUSED*/ | |
786 | vi_repeat_prev_char(EditLine *el, Int c __attribute__((__unused__))) | 786 | vi_repeat_prev_char(EditLine *el, Int c __attribute__((__unused__))) | |
787 | { | 787 | { | |
788 | el_action_t r; | 788 | el_action_t r; | |
789 | int dir = el->el_search.chadir; | 789 | int dir = el->el_search.chadir; | |
790 | 790 | |||
791 | r = cv_csearch(el, -dir, el->el_search.chacha, | 791 | r = cv_csearch(el, -dir, el->el_search.chacha, | |
792 | el->el_state.argument, el->el_search.chatflg); | 792 | el->el_state.argument, el->el_search.chatflg); | |
793 | el->el_search.chadir = dir; | 793 | el->el_search.chadir = dir; | |
794 | return r; | 794 | return r; | |
795 | } | 795 | } | |
796 | 796 | |||
797 | 797 | |||
798 | /* vi_match(): | 798 | /* vi_match(): | |
799 | * Vi go to matching () {} or [] | 799 | * Vi go to matching () {} or [] | |
800 | * [%] | 800 | * [%] | |
801 | */ | 801 | */ | |
802 | protected el_action_t | 802 | protected el_action_t | |
803 | /*ARGSUSED*/ | 803 | /*ARGSUSED*/ | |
804 | vi_match(EditLine *el, Int c) | 804 | vi_match(EditLine *el, Int c __attribute__((__unused__))) | |
805 | { | 805 | { | |
806 | const Char match_chars[] = STR("()[]{}"); | 806 | const Char match_chars[] = STR("()[]{}"); | |
807 | Char *cp; | 807 | Char *cp; | |
808 | size_t delta, i, count; | 808 | size_t delta, i, count; | |
809 | Char o_ch, c_ch; | 809 | Char o_ch, c_ch; | |
810 | 810 | |||
811 | *el->el_line.lastchar = '\0'; /* just in case */ | 811 | *el->el_line.lastchar = '\0'; /* just in case */ | |
812 | 812 | |||
813 | i = Strcspn(el->el_line.cursor, match_chars); | 813 | i = Strcspn(el->el_line.cursor, match_chars); | |
814 | o_ch = el->el_line.cursor[i]; | 814 | o_ch = el->el_line.cursor[i]; | |
815 | if (o_ch == 0) | 815 | if (o_ch == 0) | |
816 | return CC_ERROR; | 816 | return CC_ERROR; | |
817 | delta = Strchr(match_chars, o_ch) - match_chars; | 817 | delta = Strchr(match_chars, o_ch) - match_chars; | |
818 | c_ch = match_chars[delta ^ 1]; | 818 | c_ch = match_chars[delta ^ 1]; | |
819 | count = 1; | 819 | count = 1; | |
820 | delta = 1 - (delta & 1) * 2; | 820 | delta = 1 - (delta & 1) * 2; | |
821 | 821 | |||
822 | for (cp = &el->el_line.cursor[i]; count; ) { | 822 | for (cp = &el->el_line.cursor[i]; count; ) { | |
823 | cp += delta; | 823 | cp += delta; | |
824 | if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) | 824 | if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) | |
825 | return CC_ERROR; | 825 | return CC_ERROR; | |
826 | if (*cp == o_ch) | 826 | if (*cp == o_ch) | |
827 | count++; | 827 | count++; | |
828 | else if (*cp == c_ch) | 828 | else if (*cp == c_ch) | |
829 | count--; | 829 | count--; | |
830 | } | 830 | } | |
831 | 831 | |||
832 | el->el_line.cursor = cp; | 832 | el->el_line.cursor = cp; | |
833 | 833 | |||
834 | if (el->el_chared.c_vcmd.action != NOP) { | 834 | if (el->el_chared.c_vcmd.action != NOP) { | |
835 | /* NB posix says char under cursor should NOT be deleted | 835 | /* NB posix says char under cursor should NOT be deleted | |
836 | for -ve delta - this is different to netbsd vi. */ | 836 | for -ve delta - this is different to netbsd vi. */ | |
837 | if (delta > 0) | 837 | if (delta > 0) | |
838 | el->el_line.cursor++; | 838 | el->el_line.cursor++; | |
839 | cv_delfini(el); | 839 | cv_delfini(el); | |
840 | return CC_REFRESH; | 840 | return CC_REFRESH; | |
841 | } | 841 | } | |
842 | return CC_CURSOR; | 842 | return CC_CURSOR; | |
843 | } | 843 | } | |
844 | 844 | |||
845 | /* vi_undo_line(): | 845 | /* vi_undo_line(): | |
846 | * Vi undo all changes to line | 846 | * Vi undo all changes to line | |
847 | * [U] | 847 | * [U] | |
848 | */ | 848 | */ | |
849 | protected el_action_t | 849 | protected el_action_t | |
850 | /*ARGSUSED*/ | 850 | /*ARGSUSED*/ | |
851 | vi_undo_line(EditLine *el, Int c) | 851 | vi_undo_line(EditLine *el, Int c __attribute__((__unused__))) | |
852 | { | 852 | { | |
853 | 853 | |||
854 | cv_undo(el); | 854 | cv_undo(el); | |
855 | return hist_get(el); | 855 | return hist_get(el); | |
856 | } | 856 | } | |
857 | 857 | |||
858 | /* vi_to_column(): | 858 | /* vi_to_column(): | |
859 | * Vi go to specified column | 859 | * Vi go to specified column | |
860 | * [|] | 860 | * [|] | |
861 | * NB netbsd vi goes to screen column 'n', posix says nth character | 861 | * NB netbsd vi goes to screen column 'n', posix says nth character | |
862 | */ | 862 | */ | |
863 | protected el_action_t | 863 | protected el_action_t | |
864 | /*ARGSUSED*/ | 864 | /*ARGSUSED*/ | |
865 | vi_to_column(EditLine *el, Int c) | 865 | vi_to_column(EditLine *el, Int c __attribute__((__unused__))) | |
866 | { | 866 | { | |
867 | 867 | |||
868 | el->el_line.cursor = el->el_line.buffer; | 868 | el->el_line.cursor = el->el_line.buffer; | |
869 | el->el_state.argument--; | 869 | el->el_state.argument--; | |
870 | return ed_next_char(el, 0); | 870 | return ed_next_char(el, 0); | |
871 | } | 871 | } | |
872 | 872 | |||
873 | /* vi_yank_end(): | 873 | /* vi_yank_end(): | |
874 | * Vi yank to end of line | 874 | * Vi yank to end of line | |
875 | * [Y] | 875 | * [Y] | |
876 | */ | 876 | */ | |
877 | protected el_action_t | 877 | protected el_action_t | |
878 | /*ARGSUSED*/ | 878 | /*ARGSUSED*/ | |
879 | vi_yank_end(EditLine *el, Int c) | 879 | vi_yank_end(EditLine *el, Int c __attribute__((__unused__))) | |
880 | { | 880 | { | |
881 | 881 | |||
882 | cv_yank(el, el->el_line.cursor, | 882 | cv_yank(el, el->el_line.cursor, | |
883 | (int)(el->el_line.lastchar - el->el_line.cursor)); | 883 | (int)(el->el_line.lastchar - el->el_line.cursor)); | |
884 | return CC_REFRESH; | 884 | return CC_REFRESH; | |
885 | } | 885 | } | |
886 | 886 | |||
887 | /* vi_yank(): | 887 | /* vi_yank(): | |
888 | * Vi yank | 888 | * Vi yank | |
889 | * [y] | 889 | * [y] | |
890 | */ | 890 | */ | |
891 | protected el_action_t | 891 | protected el_action_t | |
892 | /*ARGSUSED*/ | 892 | /*ARGSUSED*/ | |
893 | vi_yank(EditLine *el, Int c) | 893 | vi_yank(EditLine *el, Int c __attribute__((__unused__))) | |
894 | { | 894 | { | |
895 | 895 | |||
896 | return cv_action(el, YANK); | 896 | return cv_action(el, YANK); | |
897 | } | 897 | } | |
898 | 898 | |||
899 | /* vi_comment_out(): | 899 | /* vi_comment_out(): | |
900 | * Vi comment out current command | 900 | * Vi comment out current command | |
901 | * [#] | 901 | * [#] | |
902 | */ | 902 | */ | |
903 | protected el_action_t | 903 | protected el_action_t | |
904 | /*ARGSUSED*/ | 904 | /*ARGSUSED*/ | |
905 | vi_comment_out(EditLine *el, Int c) | 905 | vi_comment_out(EditLine *el, Int c __attribute__((__unused__))) | |
906 | { | 906 | { | |
907 | 907 | |||
908 | el->el_line.cursor = el->el_line.buffer; | 908 | el->el_line.cursor = el->el_line.buffer; | |
909 | c_insert(el, 1); | 909 | c_insert(el, 1); | |
910 | *el->el_line.cursor = '#'; | 910 | *el->el_line.cursor = '#'; | |
911 | re_refresh(el); | 911 | re_refresh(el); | |
912 | return ed_newline(el, 0); | 912 | return ed_newline(el, 0); | |
913 | } | 913 | } | |
914 | 914 | |||
915 | /* vi_alias(): | 915 | /* vi_alias(): | |
916 | * Vi include shell alias | 916 | * Vi include shell alias | |
917 | * [@] | 917 | * [@] | |
918 | * NB: posix implies that we should enter insert mode, however | 918 | * NB: posix implies that we should enter insert mode, however | |
919 | * this is against historical precedent... | 919 | * this is against historical precedent... | |
920 | */ | 920 | */ | |
921 | #ifdef __weak_reference | 921 | #ifdef __weak_reference | |
922 | __weakref_visible char *my_get_alias_text(const char *) | 922 | __weakref_visible char *my_get_alias_text(const char *) | |
923 | __weak_reference(get_alias_text); | 923 | __weak_reference(get_alias_text); | |
924 | #endif | 924 | #endif | |
925 | protected el_action_t | 925 | protected el_action_t | |
926 | /*ARGSUSED*/ | 926 | /*ARGSUSED*/ | |
927 | vi_alias(EditLine *el, Int c) | 927 | vi_alias(EditLine *el, Int c __attribute__((__unused__))) | |
928 | { | 928 | { | |
929 | #ifdef __weak_reference | 929 | #ifdef __weak_reference | |
930 | char alias_name[3]; | 930 | char alias_name[3]; | |
931 | char *alias_text; | 931 | char *alias_text; | |
932 | 932 | |||
933 | if (my_get_alias_text == 0) { | 933 | if (my_get_alias_text == 0) { | |
934 | return CC_ERROR; | 934 | return CC_ERROR; | |
935 | } | 935 | } | |
936 | 936 | |||
937 | alias_name[0] = '_'; | 937 | alias_name[0] = '_'; | |
938 | alias_name[2] = 0; | 938 | alias_name[2] = 0; | |
939 | if (el_getc(el, &alias_name[1]) != 1) | 939 | if (el_getc(el, &alias_name[1]) != 1) | |
940 | return CC_ERROR; | 940 | return CC_ERROR; | |
941 | 941 | |||
942 | alias_text = my_get_alias_text(alias_name); | 942 | alias_text = my_get_alias_text(alias_name); | |
943 | if (alias_text != NULL) | 943 | if (alias_text != NULL) | |
944 | FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch)); | 944 | FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch)); | |
945 | return CC_NORM; | 945 | return CC_NORM; | |
946 | #else | 946 | #else | |
947 | return CC_ERROR; | 947 | return CC_ERROR; | |
948 | #endif | 948 | #endif | |
949 | } | 949 | } | |
950 | 950 | |||
951 | /* vi_to_history_line(): | 951 | /* vi_to_history_line(): | |
952 | * Vi go to specified history file line. | 952 | * Vi go to specified history file line. | |
953 | * [G] | 953 | * [G] | |
954 | */ | 954 | */ | |
955 | protected el_action_t | 955 | protected el_action_t | |
956 | /*ARGSUSED*/ | 956 | /*ARGSUSED*/ | |
957 | vi_to_history_line(EditLine *el, Int c) | 957 | vi_to_history_line(EditLine *el, Int c __attribute__((__unused__))) | |
958 | { | 958 | { | |
959 | int sv_event_no = el->el_history.eventno; | 959 | int sv_event_no = el->el_history.eventno; | |
960 | el_action_t rval; | 960 | el_action_t rval; | |
961 | 961 | |||
962 | 962 | |||
963 | if (el->el_history.eventno == 0) { | 963 | if (el->el_history.eventno == 0) { | |
964 | (void) Strncpy(el->el_history.buf, el->el_line.buffer, | 964 | (void) Strncpy(el->el_history.buf, el->el_line.buffer, | |
965 | EL_BUFSIZ); | 965 | EL_BUFSIZ); | |
966 | el->el_history.last = el->el_history.buf + | 966 | el->el_history.last = el->el_history.buf + | |
967 | (el->el_line.lastchar - el->el_line.buffer); | 967 | (el->el_line.lastchar - el->el_line.buffer); | |
968 | } | 968 | } | |
969 | 969 | |||
970 | /* Lack of a 'count' means oldest, not 1 */ | 970 | /* Lack of a 'count' means oldest, not 1 */ | |
971 | if (!el->el_state.doingarg) { | 971 | if (!el->el_state.doingarg) { | |
972 | el->el_history.eventno = 0x7fffffff; | 972 | el->el_history.eventno = 0x7fffffff; | |
973 | hist_get(el); | 973 | hist_get(el); | |
974 | } else { | 974 | } else { | |
975 | /* This is brain dead, all the rest of this code counts | 975 | /* This is brain dead, all the rest of this code counts | |
976 | * upwards going into the past. Here we need count in the | 976 | * upwards going into the past. Here we need count in the | |
977 | * other direction (to match the output of fc -l). | 977 | * other direction (to match the output of fc -l). | |
978 | * I could change the world, but this seems to suffice. | 978 | * I could change the world, but this seems to suffice. | |
979 | */ | 979 | */ | |
980 | el->el_history.eventno = 1; | 980 | el->el_history.eventno = 1; | |
981 | if (hist_get(el) == CC_ERROR) | 981 | if (hist_get(el) == CC_ERROR) | |
982 | return CC_ERROR; | 982 | return CC_ERROR; | |
983 | el->el_history.eventno = 1 + el->el_history.ev.num | 983 | el->el_history.eventno = 1 + el->el_history.ev.num | |
984 | - el->el_state.argument; | 984 | - el->el_state.argument; | |
985 | if (el->el_history.eventno < 0) { | 985 | if (el->el_history.eventno < 0) { | |
986 | el->el_history.eventno = sv_event_no; | 986 | el->el_history.eventno = sv_event_no; | |
987 | return CC_ERROR; | 987 | return CC_ERROR; | |
988 | } | 988 | } | |
989 | } | 989 | } | |
990 | rval = hist_get(el); | 990 | rval = hist_get(el); | |
991 | if (rval == CC_ERROR) | 991 | if (rval == CC_ERROR) | |
992 | el->el_history.eventno = sv_event_no; | 992 | el->el_history.eventno = sv_event_no; | |
993 | return rval; | 993 | return rval; | |
994 | } | 994 | } | |
995 | 995 | |||
996 | /* vi_histedit(): | 996 | /* vi_histedit(): | |
997 | * Vi edit history line with vi | 997 | * Vi edit history line with vi | |
998 | * [v] | 998 | * [v] | |
999 | */ | 999 | */ | |
1000 | protected el_action_t | 1000 | protected el_action_t | |
1001 | /*ARGSUSED*/ | 1001 | /*ARGSUSED*/ | |
1002 | vi_histedit(EditLine *el, Int c) | 1002 | vi_histedit(EditLine *el, Int c __attribute__((__unused__))) | |
1003 | { | 1003 | { | |
1004 | int fd; | 1004 | int fd; | |
1005 | pid_t pid; | 1005 | pid_t pid; | |
1006 | ssize_t st; | 1006 | ssize_t st; | |
1007 | int status; | 1007 | int status; | |
1008 | char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; | 1008 | char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; | |
1009 | char *cp; | 1009 | char *cp; | |
1010 | size_t len; | 1010 | size_t len; | |
1011 | Char *line; | 1011 | Char *line; | |
1012 | 1012 | |||
1013 | if (el->el_state.doingarg) { | 1013 | if (el->el_state.doingarg) { | |
1014 | if (vi_to_history_line(el, 0) == CC_ERROR) | 1014 | if (vi_to_history_line(el, 0) == CC_ERROR) | |
1015 | return CC_ERROR; | 1015 | return CC_ERROR; | |
1016 | } | 1016 | } | |
1017 | 1017 | |||
1018 | fd = mkstemp(tempfile); | 1018 | fd = mkstemp(tempfile); | |
1019 | if (fd < 0) | 1019 | if (fd < 0) | |
1020 | return CC_ERROR; | 1020 | return CC_ERROR; | |
1021 | len = (size_t)(el->el_line.lastchar - el->el_line.buffer); | 1021 | len = (size_t)(el->el_line.lastchar - el->el_line.buffer); | |
1022 | #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) | 1022 | #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) | |
1023 | cp = el_malloc(TMP_BUFSIZ * sizeof(*cp)); | 1023 | cp = el_malloc(TMP_BUFSIZ * sizeof(*cp)); | |
1024 | if (cp == NULL) { | 1024 | if (cp == NULL) { | |
1025 | unlink(tempfile); | 1025 | unlink(tempfile); | |
1026 | close(fd); | 1026 | close(fd); | |
1027 | return CC_ERROR; | 1027 | return CC_ERROR; | |
1028 | } | 1028 | } | |
1029 | line = el_malloc(len * sizeof(*line)); | 1029 | line = el_malloc(len * sizeof(*line)); | |
1030 | if (line == NULL) { | 1030 | if (line == NULL) { | |
1031 | el_free(cp); | 1031 | el_free(cp); | |
1032 | return CC_ERROR; | 1032 | return CC_ERROR; | |
1033 | } | 1033 | } | |
1034 | Strncpy(line, el->el_line.buffer, len); | 1034 | Strncpy(line, el->el_line.buffer, len); | |
1035 | line[len] = '\0'; | 1035 | line[len] = '\0'; | |
1036 | ct_wcstombs(cp, line, TMP_BUFSIZ - 1); | 1036 | ct_wcstombs(cp, line, TMP_BUFSIZ - 1); | |
1037 | cp[TMP_BUFSIZ - 1] = '\0'; | 1037 | cp[TMP_BUFSIZ - 1] = '\0'; | |
1038 | len = strlen(cp); | 1038 | len = strlen(cp); | |
1039 | write(fd, cp, len); | 1039 | write(fd, cp, len); | |
1040 | write(fd, "\n", 1); | 1040 | write(fd, "\n", 1); | |
1041 | pid = fork(); | 1041 | pid = fork(); | |
1042 | switch (pid) { | 1042 | switch (pid) { | |
1043 | case -1: | 1043 | case -1: | |
1044 | close(fd); | 1044 | close(fd); | |
1045 | unlink(tempfile); | 1045 | unlink(tempfile); | |
1046 | el_free(cp); | 1046 | el_free(cp); | |
1047 | el_free(line); | 1047 | el_free(line); | |
1048 | return CC_ERROR; | 1048 | return CC_ERROR; | |
1049 | case 0: | 1049 | case 0: | |
1050 | close(fd); | 1050 | close(fd); | |
1051 | execlp("vi", "vi", tempfile, (char *)NULL); | 1051 | execlp("vi", "vi", tempfile, (char *)NULL); | |
1052 | exit(0); | 1052 | exit(0); | |
1053 | /*NOTREACHED*/ | 1053 | /*NOTREACHED*/ | |
1054 | default: | 1054 | default: | |
1055 | while (waitpid(pid, &status, 0) != pid) | 1055 | while (waitpid(pid, &status, 0) != pid) | |
1056 | continue; | 1056 | continue; | |
1057 | lseek(fd, (off_t)0, SEEK_SET); | 1057 | lseek(fd, (off_t)0, SEEK_SET); | |
1058 | st = read(fd, cp, TMP_BUFSIZ); | 1058 | st = read(fd, cp, TMP_BUFSIZ); | |
1059 | if (st > 0) { | 1059 | if (st > 0) { | |
1060 | len = (size_t)(el->el_line.lastchar - | 1060 | len = (size_t)(el->el_line.lastchar - | |
1061 | el->el_line.buffer); | 1061 | el->el_line.buffer); | |
1062 | len = ct_mbstowcs(el->el_line.buffer, cp, len); | 1062 | len = ct_mbstowcs(el->el_line.buffer, cp, len); | |
1063 | if (len > 0 && el->el_line.buffer[len -1] == '\n') | 1063 | if (len > 0 && el->el_line.buffer[len -1] == '\n') | |
1064 | --len; | 1064 | --len; | |
1065 | } | 1065 | } | |
1066 | else | 1066 | else | |
1067 | len = 0; | 1067 | len = 0; | |
1068 | el->el_line.cursor = el->el_line.buffer; | 1068 | el->el_line.cursor = el->el_line.buffer; | |
1069 | el->el_line.lastchar = el->el_line.buffer + len; | 1069 | el->el_line.lastchar = el->el_line.buffer + len; | |
1070 | el_free(cp); | 1070 | el_free(cp); | |
1071 | el_free(line); | 1071 | el_free(line); | |
1072 | break; | 1072 | break; | |
1073 | } | 1073 | } | |
1074 | 1074 | |||
1075 | close(fd); | 1075 | close(fd); | |
1076 | unlink(tempfile); | 1076 | unlink(tempfile); | |
1077 | /* return CC_REFRESH; */ | 1077 | /* return CC_REFRESH; */ | |
1078 | return ed_newline(el, 0); | 1078 | return ed_newline(el, 0); | |
1079 | } | 1079 | } | |
1080 | 1080 | |||
1081 | /* vi_history_word(): | 1081 | /* vi_history_word(): | |
1082 | * Vi append word from previous input line | 1082 | * Vi append word from previous input line | |
1083 | * [_] | 1083 | * [_] | |
1084 | * Who knows where this one came from! | 1084 | * Who knows where this one came from! | |
1085 | * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' | 1085 | * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' | |
1086 | */ | 1086 | */ | |
1087 | protected el_action_t | 1087 | protected el_action_t | |
1088 | /*ARGSUSED*/ | 1088 | /*ARGSUSED*/ | |
1089 | vi_history_word(EditLine *el, Int c) | 1089 | vi_history_word(EditLine *el, Int c __attribute__((__unused__))) | |
1090 | { | 1090 | { | |
1091 | const Char *wp = HIST_FIRST(el); | 1091 | const Char *wp = HIST_FIRST(el); | |
1092 | const Char *wep, *wsp; | 1092 | const Char *wep, *wsp; | |
1093 | int len; | 1093 | int len; | |
1094 | Char *cp; | 1094 | Char *cp; | |
1095 | const Char *lim; | 1095 | const Char *lim; | |
1096 | 1096 | |||
1097 | if (wp == NULL) | 1097 | if (wp == NULL) | |
1098 | return CC_ERROR; | 1098 | return CC_ERROR; | |
1099 | 1099 | |||
1100 | wep = wsp = 0; | 1100 | wep = wsp = 0; | |
1101 | do { | 1101 | do { | |
1102 | while (Isspace(*wp)) | 1102 | while (Isspace(*wp)) | |
1103 | wp++; | 1103 | wp++; | |
1104 | if (*wp == 0) | 1104 | if (*wp == 0) | |
1105 | break; | 1105 | break; | |
1106 | wsp = wp; | 1106 | wsp = wp; | |
1107 | while (*wp && !Isspace(*wp)) | 1107 | while (*wp && !Isspace(*wp)) | |
1108 | wp++; | 1108 | wp++; | |
1109 | wep = wp; | 1109 | wep = wp; | |
1110 | } while ((!el->el_state.doingarg || --el->el_state.argument > 0) | 1110 | } while ((!el->el_state.doingarg || --el->el_state.argument > 0) | |
1111 | && *wp != 0); | 1111 | && *wp != 0); | |
1112 | 1112 | |||
1113 | if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) | 1113 | if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) | |
1114 | return CC_ERROR; | 1114 | return CC_ERROR; | |
1115 | 1115 | |||
1116 | cv_undo(el); | 1116 | cv_undo(el); | |
1117 | len = (int)(wep - wsp); | 1117 | len = (int)(wep - wsp); | |
1118 | if (el->el_line.cursor < el->el_line.lastchar) | 1118 | if (el->el_line.cursor < el->el_line.lastchar) | |
1119 | el->el_line.cursor++; | 1119 | el->el_line.cursor++; | |
1120 | c_insert(el, len + 1); | 1120 | c_insert(el, len + 1); | |
1121 | cp = el->el_line.cursor; | 1121 | cp = el->el_line.cursor; | |
1122 | lim = el->el_line.limit; | 1122 | lim = el->el_line.limit; | |
1123 | if (cp < lim) | 1123 | if (cp < lim) | |
1124 | *cp++ = ' '; | 1124 | *cp++ = ' '; | |
1125 | while (wsp < wep && cp < lim) | 1125 | while (wsp < wep && cp < lim) | |
1126 | *cp++ = *wsp++; | 1126 | *cp++ = *wsp++; | |
1127 | el->el_line.cursor = cp; | 1127 | el->el_line.cursor = cp; | |
1128 | 1128 | |||
1129 | el->el_map.current = el->el_map.key; | 1129 | el->el_map.current = el->el_map.key; | |
1130 | return CC_REFRESH; | 1130 | return CC_REFRESH; | |
1131 | } | 1131 | } | |
1132 | 1132 | |||
1133 | /* vi_redo(): | 1133 | /* vi_redo(): | |
1134 | * Vi redo last non-motion command | 1134 | * Vi redo last non-motion command | |
1135 | * [.] | 1135 | * [.] | |
1136 | */ | 1136 | */ | |
1137 | protected el_action_t | 1137 | protected el_action_t | |
1138 | /*ARGSUSED*/ | 1138 | /*ARGSUSED*/ | |
1139 | vi_redo(EditLine *el, Int c) | 1139 | vi_redo(EditLine *el, Int c __attribute__((__unused__))) | |
1140 | { | 1140 | { | |
1141 | c_redo_t *r = &el->el_chared.c_redo; | 1141 | c_redo_t *r = &el->el_chared.c_redo; | |
1142 | 1142 | |||
1143 | if (!el->el_state.doingarg && r->count) { | 1143 | if (!el->el_state.doingarg && r->count) { | |
1144 | el->el_state.doingarg = 1; | 1144 | el->el_state.doingarg = 1; | |
1145 | el->el_state.argument = r->count; | 1145 | el->el_state.argument = r->count; | |
1146 | } | 1146 | } | |
1147 | 1147 | |||
1148 | el->el_chared.c_vcmd.pos = el->el_line.cursor; | 1148 | el->el_chared.c_vcmd.pos = el->el_line.cursor; | |
1149 | el->el_chared.c_vcmd.action = r->action; | 1149 | el->el_chared.c_vcmd.action = r->action; | |
1150 | if (r->pos != r->buf) { | 1150 | if (r->pos != r->buf) { | |
1151 | if (r->pos + 1 > r->lim) | 1151 | if (r->pos + 1 > r->lim) | |
1152 | /* sanity */ | 1152 | /* sanity */ | |
1153 | r->pos = r->lim - 1; | 1153 | r->pos = r->lim - 1; | |
1154 | r->pos[0] = 0; | 1154 | r->pos[0] = 0; | |
1155 | FUN(el,push)(el, r->buf); | 1155 | FUN(el,push)(el, r->buf); | |
1156 | } | 1156 | } | |
1157 | 1157 | |||
1158 | el->el_state.thiscmd = r->cmd; | 1158 | el->el_state.thiscmd = r->cmd; | |
1159 | el->el_state.thisch = r->ch; | 1159 | el->el_state.thisch = r->ch; | |
1160 | return (*el->el_map.func[r->cmd])(el, r->ch); | 1160 | return (*el->el_map.func[r->cmd])(el, r->ch); | |
1161 | } | 1161 | } |