File: | src/usr.bin/vi/build/../vi/vi.c |
Warning: | line 1129, column 10 Although the value stored to 'tc' is used in the enclosing expression, the value is never actually read from 'tc' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: vi.c,v 1.23 2022/02/20 19:45:51 tb Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1992, 1993, 1994 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * Copyright (c) 1992, 1993, 1994, 1995, 1996 |
7 | * Keith Bostic. All rights reserved. |
8 | * |
9 | * See the LICENSE file for redistribution information. |
10 | */ |
11 | |
12 | #include "config.h" |
13 | |
14 | #include <sys/types.h> |
15 | #include <sys/queue.h> |
16 | #include <sys/time.h> |
17 | |
18 | #include <bitstring.h> |
19 | #include <ctype.h> |
20 | #include <errno(*__errno()).h> |
21 | #include <limits.h> |
22 | #include <stdio.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <unistd.h> |
26 | |
27 | #include "../common/common.h" |
28 | #include "vi.h" |
29 | |
30 | typedef enum { |
31 | GC_ERR, GC_ERR_NOFLUSH, GC_EVENT, GC_FATAL, GC_INTERRUPT, GC_OK |
32 | } gcret_t; |
33 | |
34 | static VIKEYS const |
35 | *v_alias(SCR *, VICMD *, VIKEYS const *); |
36 | static gcret_t v_cmd(SCR *, VICMD *, VICMD *, VICMD *, int *, int *); |
37 | static int v_count(SCR *, CHAR_T, u_long *); |
38 | static void v_dtoh(SCR *); |
39 | static int v_init(SCR *); |
40 | static gcret_t v_key(SCR *, int, EVENT *, u_int32_t); |
41 | static int v_keyword(SCR *); |
42 | static int v_motion(SCR *, VICMD *, VICMD *, int *); |
43 | |
44 | #if defined(DEBUG) && defined(COMLOG) |
45 | static void v_comlog(SCR *, VICMD *); |
46 | #endif |
47 | |
48 | /* |
49 | * Side-effect: |
50 | * The dot structure can be set by the underlying vi functions, |
51 | * see v_Put() and v_put(). |
52 | */ |
53 | #define DOT(&((VI_PRIVATE *)((sp)->vi_private))->sdot) (&VIP(sp)((VI_PRIVATE *)((sp)->vi_private))->sdot) |
54 | #define DOTMOTION(&((VI_PRIVATE *)((sp)->vi_private))->sdotmotion) (&VIP(sp)((VI_PRIVATE *)((sp)->vi_private))->sdotmotion) |
55 | |
56 | /* |
57 | * vi -- |
58 | * Main vi command loop. |
59 | * |
60 | * PUBLIC: int vi(SCR **); |
61 | */ |
62 | int |
63 | vi(SCR **spp) |
64 | { |
65 | GS *gp; |
66 | MARK abs; |
67 | SCR *next, *sp; |
68 | VICMD cmd, *vp; |
69 | VI_PRIVATE *vip; |
70 | int comcount, mapped, rval; |
71 | |
72 | /* Get the first screen. */ |
73 | sp = *spp; |
74 | gp = sp->gp; |
75 | |
76 | /* Initialize the command structure. */ |
77 | vp = &cmd; |
78 | memset(vp, 0, sizeof(VICMD)); |
79 | |
80 | /* Reset strange attraction. */ |
81 | F_SET(vp, VM_RCM_SET)(((vp)->flags) |= ((0x00000020))); |
82 | |
83 | /* Initialize the vi screen. */ |
84 | if (v_init(sp)) |
85 | return (1); |
86 | |
87 | /* Set the focus. */ |
88 | (void)sp->gp->scr_rename(sp, sp->frp->name, 1); |
89 | |
90 | for (vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)), rval = 0;;) { |
91 | /* Resolve messages. */ |
92 | if (!MAPPED_KEYS_WAITING(sp)(((sp)->gp->i_cnt != 0) && (((&(sp)->gp-> i_event[(sp)->gp->i_next]._u_event._e_ch)->flags) & ((0x02)))) && vs_resolve(sp, NULL((void *)0), 0)) |
93 | goto ret; |
94 | |
95 | /* |
96 | * If not skipping a refresh, return to command mode and |
97 | * refresh the screen. |
98 | */ |
99 | if (F_ISSET(vip, VIP_S_REFRESH)(((vip)->flags) & ((0x0100)))) |
100 | F_CLR(vip, VIP_S_REFRESH)(((vip)->flags) &= ~((0x0100))); |
101 | else { |
102 | sp->showmode = SM_COMMAND; |
103 | if (vs_refresh(sp, 0)) |
104 | goto ret; |
105 | } |
106 | |
107 | /* Set the new favorite position. */ |
108 | if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)(((vp)->flags) & ((0x00000020 | 0x00000040 | 0x00000100 )))) { |
109 | F_CLR(vip, VIP_RCM_LAST)(((vip)->flags) &= ~((0x0040))); |
110 | (void)vs_column(sp, &sp->rcm); |
111 | } |
112 | |
113 | /* |
114 | * If not currently in a map, log the cursor position, |
115 | * and set a flag so that this command can become the |
116 | * DOT command. |
117 | */ |
118 | if (MAPPED_KEYS_WAITING(sp)(((sp)->gp->i_cnt != 0) && (((&(sp)->gp-> i_event[(sp)->gp->i_next]._u_event._e_ch)->flags) & ((0x02))))) |
119 | mapped = 1; |
120 | else { |
121 | if (log_cursor(sp)) |
122 | goto err; |
123 | mapped = 0; |
124 | } |
125 | |
126 | /* |
127 | * There may be an ex command waiting, and we returned here |
128 | * only because we exited a screen or file. In this case, |
129 | * we simply go back into the ex parser. |
130 | */ |
131 | if (EXCMD_RUNNING(gp)(((&(gp)->ecq)->lh_first)->clen != 0)) { |
132 | vp->kp = &vikeys[':']; |
133 | goto ex_continue; |
134 | } |
135 | |
136 | /* Refresh the command structure. */ |
137 | memset(vp, 0, sizeof(VICMD)); |
138 | |
139 | /* |
140 | * We get a command, which may or may not have an associated |
141 | * motion. If it does, we get it too, calling its underlying |
142 | * function to get the resulting mark. We then call the |
143 | * command setting the cursor to the resulting mark. |
144 | * |
145 | * !!! |
146 | * Vi historically flushed mapped characters on error, but |
147 | * entering extra <escape> characters at the beginning of |
148 | * a map wasn't considered an error -- in fact, users would |
149 | * put leading <escape> characters in maps to clean up vi |
150 | * state before the map was interpreted. Beauty! |
151 | */ |
152 | switch (v_cmd(sp, DOT(&((VI_PRIVATE *)((sp)->vi_private))->sdot), vp, NULL((void *)0), &comcount, &mapped)) { |
153 | case GC_ERR: |
154 | goto err; |
155 | case GC_ERR_NOFLUSH: |
156 | goto gc_err_noflush; |
157 | case GC_EVENT: |
158 | if (v_event_exec(sp, vp)) |
159 | goto err; |
160 | goto gc_event; |
161 | case GC_FATAL: |
162 | goto ret; |
163 | case GC_INTERRUPT: |
164 | goto intr; |
165 | case GC_OK: |
166 | break; |
167 | } |
168 | |
169 | /* Check for security setting. */ |
170 | if (F_ISSET(vp->kp, V_SECURE)(((vp->kp)->flags) & ((0x02000000))) && O_ISSET(sp, O_SECURE)((((&(((sp)))->opts[(((O_SECURE)))])->flags) & ( (0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_SECURE )))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_SECURE)))] .o_cur.val)) { |
171 | ex_emsg(sp, KEY_NAME(sp, vp->key)((unsigned char)(vp->key) <= 254 ? (sp)->gp->cname [(unsigned char)(vp->key)].name : v_key_name((sp), (vp-> key))), EXM_SECURE); |
172 | goto err; |
173 | } |
174 | |
175 | /* |
176 | * Historical practice: if a dot command gets a new count, |
177 | * any motion component goes away, i.e. "d3w2." deletes a |
178 | * total of 5 words. |
179 | */ |
180 | if (F_ISSET(vp, VC_ISDOT)(((vp)->flags) & ((0x00002000))) && comcount) |
181 | DOTMOTION(&((VI_PRIVATE *)((sp)->vi_private))->sdotmotion)->count = 1; |
182 | |
183 | /* Copy the key flags into the local structure. */ |
184 | F_SET(vp, vp->kp->flags)(((vp)->flags) |= ((vp->kp->flags))); |
185 | |
186 | /* Prepare to set the previous context. */ |
187 | if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)(((vp)->flags) & ((0x00004000 | 0x00008000 | 0x00010000 )))) { |
188 | abs.lno = sp->lno; |
189 | abs.cno = sp->cno; |
190 | } |
191 | |
192 | /* |
193 | * Set the three cursor locations to the current cursor. The |
194 | * underlying routines don't bother if the cursor doesn't move. |
195 | * This also handles line commands (e.g. Y) defaulting to the |
196 | * current line. |
197 | */ |
198 | vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno; |
199 | vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno; |
200 | |
201 | /* |
202 | * Do any required motion; v_motion sets the from MARK and the |
203 | * line mode flag, as well as the VM_RCM flags. |
204 | */ |
205 | if (F_ISSET(vp, V_MOTION)(((vp)->flags) & ((0x00200000))) && |
206 | v_motion(sp, DOTMOTION(&((VI_PRIVATE *)((sp)->vi_private))->sdotmotion), vp, &mapped)) { |
207 | if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get ((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)-> flags) & ((0x0004)))))) |
208 | goto intr; |
209 | goto err; |
210 | } |
211 | |
212 | /* |
213 | * If a count is set and the command is line oriented, set the |
214 | * to MARK here relative to the cursor/from MARK. This is for |
215 | * commands that take both counts and motions, i.e. "4yy" and |
216 | * "y%". As there's no way the command can know which the user |
217 | * did, we have to do it here. (There are commands that are |
218 | * line oriented and that take counts ("#G", "#H"), for which |
219 | * this calculation is either completely meaningless or wrong. |
220 | * Each command must validate the value for itself. |
221 | */ |
222 | if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800))) && F_ISSET(vp, VM_LMODE)(((vp)->flags) & ((0x00000008)))) |
223 | vp->m_stop.lno += vp->count - 1; |
224 | |
225 | /* Increment the command count. */ |
226 | ++sp->ccnt; |
227 | |
228 | #if defined(DEBUG) && defined(COMLOG) |
229 | v_comlog(sp, vp); |
230 | #endif |
231 | /* Call the function. */ |
232 | ex_continue: if (vp->kp->func(sp, vp)) |
233 | goto err; |
234 | gc_event: |
235 | #ifdef DEBUG |
236 | /* Make sure no function left the temporary space locked. */ |
237 | if (F_ISSET(gp, G_TMP_INUSE)(((gp)->flags) & ((0x0100)))) { |
238 | F_CLR(gp, G_TMP_INUSE)(((gp)->flags) &= ~((0x0100))); |
239 | msgq(sp, M_ERR, |
240 | "vi: temporary buffer not released"); |
241 | } |
242 | #endif |
243 | /* |
244 | * If we're exiting this screen, move to the next one, or, if |
245 | * there aren't any more, return to the main editor loop. The |
246 | * ordering is careful, don't discard the contents of sp until |
247 | * the end. |
248 | */ |
249 | if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)(((sp)->flags) & ((0x00000200 | 0x00000400)))) { |
250 | if (file_end(sp, NULL((void *)0), F_ISSET(sp, SC_EXIT_FORCE)(((sp)->flags) & ((0x00000400))))) |
251 | goto ret; |
252 | if (vs_discard(sp, &next)) |
253 | goto ret; |
254 | if (next == NULL((void *)0) && vs_swap(sp, &next, NULL((void *)0))) |
255 | goto ret; |
256 | *spp = next; |
257 | if (screen_end(sp)) |
258 | goto ret; |
259 | if (next == NULL((void *)0)) |
260 | break; |
261 | |
262 | /* Switch screens, change focus. */ |
263 | sp = next; |
264 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); |
265 | (void)sp->gp->scr_rename(sp, sp->frp->name, 1); |
266 | |
267 | /* Don't trust the cursor. */ |
268 | F_SET(vip, VIP_CUR_INVALID)(((vip)->flags) |= ((0x0001))); |
269 | |
270 | continue; |
271 | } |
272 | |
273 | /* |
274 | * Set the dot command structure. |
275 | * |
276 | * !!! |
277 | * Historically, commands which used mapped keys did not |
278 | * set the dot command, with the exception of the text |
279 | * input commands. |
280 | */ |
281 | if (F_ISSET(vp, V_DOT)(((vp)->flags) & ((0x00080000))) && !mapped) { |
282 | *DOT(&((VI_PRIVATE *)((sp)->vi_private))->sdot) = cmd; |
283 | F_SET(DOT, VC_ISDOT)((((&((VI_PRIVATE *)((sp)->vi_private))->sdot))-> flags) |= ((0x00002000))); |
284 | |
285 | /* |
286 | * If a count was supplied for both the command and |
287 | * its motion, the count was used only for the motion. |
288 | * Turn the count back on for the dot structure. |
289 | */ |
290 | if (F_ISSET(vp, VC_C1RESET)(((vp)->flags) & ((0x00000400)))) |
291 | F_SET(DOT, VC_C1SET)((((&((VI_PRIVATE *)((sp)->vi_private))->sdot))-> flags) |= ((0x00000800))); |
292 | |
293 | /* VM flags aren't retained. */ |
294 | F_CLR(DOT, VM_COMMASK | VM_RCM_MASK)((((&((VI_PRIVATE *)((sp)->vi_private))->sdot))-> flags) &= ~((0x0000000f | 0x000001f0))); |
295 | } |
296 | |
297 | /* |
298 | * Some vi row movements are "attracted" to the last position |
299 | * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET |
300 | * commands' candle. If the movement is to the EOL the vi |
301 | * command handles it. If it's to the beginning, we handle it |
302 | * here. |
303 | * |
304 | * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB |
305 | * flag, but do the work themselves. The reason is that they |
306 | * have to modify the column in case they're being used as a |
307 | * motion component. Other similar commands (e.g. +, -) don't |
308 | * have to modify the column because they are always line mode |
309 | * operations when used as motions, so the column number isn't |
310 | * of any interest. |
311 | * |
312 | * Does this totally violate the screen and editor layering? |
313 | * You betcha. As they say, if you think you understand it, |
314 | * you don't. |
315 | */ |
316 | switch (F_ISSET(vp, VM_RCM_MASK)(((vp)->flags) & ((0x000001f0)))) { |
317 | case 0: |
318 | case VM_RCM_SET0x00000020: |
319 | break; |
320 | case VM_RCM0x00000010: |
321 | vp->m_final.cno = vs_rcm(sp, |
322 | vp->m_final.lno, F_ISSET(vip, VIP_RCM_LAST)(((vip)->flags) & ((0x0040)))); |
323 | break; |
324 | case VM_RCM_SETLAST0x00000080: |
325 | F_SET(vip, VIP_RCM_LAST)(((vip)->flags) |= ((0x0040))); |
326 | break; |
327 | case VM_RCM_SETFNB0x00000040: |
328 | vp->m_final.cno = 0; |
329 | /* FALLTHROUGH */ |
330 | case VM_RCM_SETNNB0x00000100: |
331 | if (nonblank(sp, vp->m_final.lno, &vp->m_final.cno)) |
332 | goto err; |
333 | break; |
334 | default: |
335 | abort(); |
336 | } |
337 | |
338 | /* Update the cursor. */ |
339 | sp->lno = vp->m_final.lno; |
340 | sp->cno = vp->m_final.cno; |
341 | |
342 | /* |
343 | * Set the absolute mark -- set even if a tags or similar |
344 | * command, since the tag may be moving to the same file. |
345 | */ |
346 | if ((F_ISSET(vp, V_ABS)(((vp)->flags) & ((0x00004000))) || |
347 | (F_ISSET(vp, V_ABS_L)(((vp)->flags) & ((0x00010000))) && sp->lno != abs.lno) || |
348 | (F_ISSET(vp, V_ABS_C)(((vp)->flags) & ((0x00008000))) && |
349 | (sp->lno != abs.lno || sp->cno != abs.cno))) && |
350 | mark_set(sp, ABSMARK1'\'', &abs, 1)) |
351 | goto err; |
352 | |
353 | if (0) { |
354 | err: if (v_event_flush(sp, CH_MAPPED0x02)) |
355 | msgq(sp, M_BERR, |
356 | "Vi command failed: mapped keys discarded"); |
357 | } |
358 | |
359 | /* |
360 | * Check and clear interrupts. There's an obvious race, but |
361 | * it's not worth fixing. |
362 | */ |
363 | gc_err_noflush: if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get ((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)-> flags) & ((0x0004)))))) { |
364 | intr: CLR_INTERRUPT(sp)((((sp)->gp)->flags) &= ~((0x0004))); |
365 | if (v_event_flush(sp, CH_MAPPED0x02)) |
366 | msgq(sp, M_ERR, |
367 | "Interrupted: mapped keys discarded"); |
368 | else |
369 | msgq(sp, M_ERR, "Interrupted"); |
370 | } |
371 | |
372 | /* If the last command switched screens, update. */ |
373 | if (F_ISSET(sp, SC_SSWITCH)(((sp)->flags) & ((0x00001000)))) { |
374 | F_CLR(sp, SC_SSWITCH)(((sp)->flags) &= ~((0x00001000))); |
375 | |
376 | /* |
377 | * If the current screen is still displayed, it will |
378 | * need a new status line. |
379 | */ |
380 | F_SET(sp, SC_STATUS)(((sp)->flags) |= ((0x02000000))); |
381 | |
382 | /* Switch screens, change focus. */ |
383 | sp = sp->nextdisp; |
384 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); |
385 | (void)sp->gp->scr_rename(sp, sp->frp->name, 1); |
386 | |
387 | /* Don't trust the cursor. */ |
388 | F_SET(vip, VIP_CUR_INVALID)(((vip)->flags) |= ((0x0001))); |
389 | |
390 | /* Refresh so we can display messages. */ |
391 | if (vs_refresh(sp, 1)) |
392 | return (1); |
393 | } |
394 | |
395 | /* If the last command switched files, change focus. */ |
396 | if (F_ISSET(sp, SC_FSWITCH)(((sp)->flags) & ((0x00000800)))) { |
397 | F_CLR(sp, SC_FSWITCH)(((sp)->flags) &= ~((0x00000800))); |
398 | F_CLR(sp, SC_SCR_TOP)(((sp)->flags) &= ~((0x00000100))); |
399 | F_SET(sp, SC_SCR_CENTER)(((sp)->flags) |= ((0x00000080))); |
400 | (void)sp->gp->scr_rename(sp, sp->frp->name, 1); |
401 | } |
402 | |
403 | /* Sync recovery if changes were made. */ |
404 | if (F_ISSET(sp->ep, F_RCV_SYNC)(((sp->ep)->flags) & ((0x100)))) |
405 | rcv_sync(sp, 0); |
406 | |
407 | /* If leaving vi, return to the main editor loop. */ |
408 | if (F_ISSET(gp, G_SRESTART)(((gp)->flags) & ((0x0080))) || F_ISSET(sp, SC_EX)(((sp)->flags) & ((0x00000001)))) { |
409 | *spp = sp; |
410 | v_dtoh(sp); |
411 | break; |
412 | } |
413 | } |
414 | if (0) |
415 | ret: rval = 1; |
416 | return (rval); |
417 | } |
418 | |
419 | #define KEY(key, ec_flags){ if ((gcret = v_key(sp, 0, &ev, (ec_flags))) != GC_OK) return (gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (key) = ev._u_event._e_ch.c; } { \ |
420 | if ((gcret = v_key(sp, 0, &ev, (ec_flags))) != GC_OK) \ |
421 | return (gcret); \ |
422 | if (ev.e_value_u_event._e_ch.value == K_ESCAPE) \ |
423 | goto esc; \ |
424 | if (F_ISSET(&ev.e_ch, CH_MAPPED)(((&ev._u_event._e_ch)->flags) & ((0x02)))) \ |
425 | *mappedp = 1; \ |
426 | (key) = ev.e_c_u_event._e_ch.c; \ |
427 | } |
428 | |
429 | /* |
430 | * The O_TILDEOP option makes the ~ command take a motion instead |
431 | * of a straight count. This is the replacement structure we use |
432 | * instead of the one currently in the VIKEYS table. |
433 | * |
434 | * XXX |
435 | * This should probably be deleted -- it's not all that useful, and |
436 | * we get help messages wrong. |
437 | */ |
438 | VIKEYS const tmotion = { |
439 | v_mulcase, V_CNT0x00040000|V_DOT0x00080000|V_MOTION0x00200000|VM_RCM_SET0x00000020, |
440 | "[count]~[count]motion", |
441 | " ~ change case to motion" |
442 | }; |
443 | |
444 | /* |
445 | * v_cmd -- |
446 | * |
447 | * The command structure for vi is less complex than ex (and don't think |
448 | * I'm not grateful!) The command syntax is: |
449 | * |
450 | * [count] [buffer] [count] key [[motion] | [buffer] [character]] |
451 | * |
452 | * and there are several special cases. The motion value is itself a vi |
453 | * command, with the syntax: |
454 | * |
455 | * [count] key [character] |
456 | */ |
457 | static gcret_t |
458 | v_cmd(SCR *sp, VICMD *dp, VICMD *vp, VICMD *ismotion, int *comcountp, |
459 | int *mappedp) |
460 | { |
461 | enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart; |
462 | EVENT ev; |
463 | VIKEYS const *kp; |
464 | gcret_t gcret; |
465 | u_int flags; |
466 | CHAR_T key; |
467 | char *s; |
468 | |
469 | /* |
470 | * Get a key. |
471 | * |
472 | * <escape> cancels partial commands, i.e. a command where at least |
473 | * one non-numeric character has been entered. Otherwise, it beeps |
474 | * the terminal. |
475 | * |
476 | * !!! |
477 | * POSIX 1003.2-1992 explicitly disallows cancelling commands where |
478 | * all that's been entered is a number, requiring that the terminal |
479 | * be alerted. |
480 | */ |
481 | cpart = ismotion == NULL((void *)0) ? COMMANDMODE : ISPARTIAL; |
482 | if ((gcret = |
483 | v_key(sp, ismotion == NULL((void *)0), &ev, EC_MAPCOMMAND0x002)) != GC_OK) { |
484 | if (gcret == GC_EVENT) |
485 | vp->ev = ev; |
486 | return (gcret); |
487 | } |
488 | if (ev.e_value_u_event._e_ch.value == K_ESCAPE) |
489 | goto esc; |
490 | if (F_ISSET(&ev.e_ch, CH_MAPPED)(((&ev._u_event._e_ch)->flags) & ((0x02)))) |
491 | *mappedp = 1; |
492 | key = ev.e_c_u_event._e_ch.c; |
493 | |
494 | if (ismotion == NULL((void *)0)) |
495 | cpart = NOTPARTIAL; |
496 | |
497 | /* Pick up optional buffer. */ |
498 | if (key == '"') { |
499 | cpart = ISPARTIAL; |
500 | if (ismotion != NULL((void *)0)) { |
501 | v_emsg(sp, NULL((void *)0), VIM_COMBUF); |
502 | return (GC_ERR); |
503 | } |
504 | KEY(vp->buffer, 0){ if ((gcret = v_key(sp, 0, &ev, (0))) != GC_OK) return ( gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (vp->buffer) = ev._u_event._e_ch.c; }; |
505 | F_SET(vp, VC_BUFFER)(((vp)->flags) |= ((0x00000200))); |
506 | |
507 | KEY(key, EC_MAPCOMMAND){ if ((gcret = v_key(sp, 0, &ev, (0x002))) != GC_OK) return (gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (key) = ev._u_event._e_ch.c; }; |
508 | } |
509 | |
510 | /* |
511 | * Pick up optional count, where a leading 0 is not a count, |
512 | * it's a command. |
513 | */ |
514 | if (isdigit(key) && key != '0') { |
515 | if (v_count(sp, key, &vp->count)) |
516 | return (GC_ERR); |
517 | F_SET(vp, VC_C1SET)(((vp)->flags) |= ((0x00000800))); |
518 | *comcountp = 1; |
519 | |
520 | KEY(key, EC_MAPCOMMAND){ if ((gcret = v_key(sp, 0, &ev, (0x002))) != GC_OK) return (gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (key) = ev._u_event._e_ch.c; }; |
521 | } else |
522 | *comcountp = 0; |
523 | |
524 | /* Pick up optional buffer. */ |
525 | if (key == '"') { |
526 | cpart = ISPARTIAL; |
527 | if (F_ISSET(vp, VC_BUFFER)(((vp)->flags) & ((0x00000200)))) { |
528 | msgq(sp, M_ERR, "Only one buffer may be specified"); |
529 | return (GC_ERR); |
530 | } |
531 | if (ismotion != NULL((void *)0)) { |
532 | v_emsg(sp, NULL((void *)0), VIM_COMBUF); |
533 | return (GC_ERR); |
534 | } |
535 | KEY(vp->buffer, 0){ if ((gcret = v_key(sp, 0, &ev, (0))) != GC_OK) return ( gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (vp->buffer) = ev._u_event._e_ch.c; }; |
536 | F_SET(vp, VC_BUFFER)(((vp)->flags) |= ((0x00000200))); |
537 | |
538 | KEY(key, EC_MAPCOMMAND){ if ((gcret = v_key(sp, 0, &ev, (0x002))) != GC_OK) return (gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (key) = ev._u_event._e_ch.c; }; |
539 | } |
540 | |
541 | /* Check for an OOB command key. */ |
542 | cpart = ISPARTIAL; |
543 | if (key > MAXVIKEY126) { |
544 | v_emsg(sp, KEY_NAME(sp, key)((unsigned char)(key) <= 254 ? (sp)->gp->cname[(unsigned char)(key)].name : v_key_name((sp), (key))), VIM_NOCOM); |
545 | return (GC_ERR); |
546 | } |
547 | kp = &vikeys[vp->key = key]; |
548 | |
549 | /* |
550 | * !!! |
551 | * Historically, D accepted and then ignored a count. Match it. |
552 | */ |
553 | if (vp->key == 'D' && F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800)))) { |
554 | *comcountp = 0; |
555 | vp->count = 0; |
556 | F_CLR(vp, VC_C1SET)(((vp)->flags) &= ~((0x00000800))); |
557 | } |
558 | |
559 | /* Check for command aliases. */ |
560 | if (kp->func == NULL((void *)0) && (kp = v_alias(sp, vp, kp)) == NULL((void *)0)) |
561 | return (GC_ERR); |
562 | |
563 | /* The tildeop option makes the ~ command take a motion. */ |
564 | if (key == '~' && O_ISSET(sp, O_TILDEOP)((((&(((sp)))->opts[(((O_TILDEOP)))])->flags) & ((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_TILDEOP )))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_TILDEOP))) ].o_cur.val)) |
565 | kp = &tmotion; |
566 | |
567 | vp->kp = kp; |
568 | |
569 | /* |
570 | * Find the command. The only legal command with no underlying |
571 | * function is dot. It's historic practice that <escape> doesn't |
572 | * just erase the preceding number, it beeps the terminal as well. |
573 | * It's a common problem, so just beep the terminal unless verbose |
574 | * was set. |
575 | */ |
576 | if (kp->func == NULL((void *)0)) { |
577 | if (key != '.') { |
578 | v_emsg(sp, KEY_NAME(sp, key)((unsigned char)(key) <= 254 ? (sp)->gp->cname[(unsigned char)(key)].name : v_key_name((sp), (key))), |
579 | ev.e_value_u_event._e_ch.value == K_ESCAPE ? VIM_NOCOM_B : VIM_NOCOM); |
580 | return (GC_ERR); |
581 | } |
582 | |
583 | /* If called for a motion command, stop now. */ |
584 | if (dp == NULL((void *)0)) |
585 | goto usage; |
586 | |
587 | /* |
588 | * !!! |
589 | * If a '.' is immediately entered after an undo command, we |
590 | * replay the log instead of redoing the last command. This |
591 | * is necessary because 'u' can't set the dot command -- see |
592 | * vi/v_undo.c:v_undo for details. |
593 | */ |
594 | if (VIP(sp)((VI_PRIVATE *)((sp)->vi_private))->u_ccnt == sp->ccnt) { |
595 | vp->kp = &vikeys['u']; |
596 | F_SET(vp, VC_ISDOT)(((vp)->flags) |= ((0x00002000))); |
597 | return (GC_OK); |
598 | } |
599 | |
600 | /* Otherwise, a repeatable command must have been executed. */ |
601 | if (!F_ISSET(dp, VC_ISDOT)(((dp)->flags) & ((0x00002000)))) { |
602 | msgq(sp, M_ERR, "No command to repeat"); |
603 | return (GC_ERR); |
604 | } |
605 | |
606 | /* Set new count/buffer, if any, and return. */ |
607 | if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800)))) { |
608 | F_SET(dp, VC_C1SET)(((dp)->flags) |= ((0x00000800))); |
609 | dp->count = vp->count; |
610 | } |
611 | if (F_ISSET(vp, VC_BUFFER)(((vp)->flags) & ((0x00000200)))) |
612 | dp->buffer = vp->buffer; |
613 | |
614 | *vp = *dp; |
615 | return (GC_OK); |
616 | } |
617 | |
618 | /* Set the flags based on the command flags. */ |
619 | flags = kp->flags; |
620 | |
621 | /* Check for illegal count. */ |
622 | if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800))) && !LF_ISSET(V_CNT)((flags) & ((0x00040000)))) |
623 | goto usage; |
624 | |
625 | /* Illegal motion command. */ |
626 | if (ismotion == NULL((void *)0)) { |
627 | /* Illegal buffer. */ |
628 | if (!LF_ISSET(V_OBUF)((flags) & ((0x00800000))) && F_ISSET(vp, VC_BUFFER)(((vp)->flags) & ((0x00000200)))) |
629 | goto usage; |
630 | |
631 | /* Required buffer. */ |
632 | if (LF_ISSET(V_RBUF)((flags) & ((0x01000000)))) { |
633 | KEY(vp->buffer, 0){ if ((gcret = v_key(sp, 0, &ev, (0))) != GC_OK) return ( gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (vp->buffer) = ev._u_event._e_ch.c; }; |
634 | F_SET(vp, VC_BUFFER)(((vp)->flags) |= ((0x00000200))); |
635 | } |
636 | } |
637 | |
638 | /* |
639 | * Special case: '[', ']' and 'Z' commands. Doesn't the fact that |
640 | * the *single* characters don't mean anything but the *doubled* |
641 | * characters do, just frost your shorts? |
642 | */ |
643 | if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') { |
644 | /* |
645 | * Historically, half entered [[, ]] or Z commands weren't |
646 | * cancelled by <escape>, the terminal was beeped instead. |
647 | * POSIX.2-1992 probably didn't notice, and requires that |
648 | * they be cancelled instead of beeping. Seems fine to me. |
649 | * |
650 | * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular |
651 | * vi meta-character, and we don't want the user to wait while |
652 | * we time out a possible mapping. This *appears* to match |
653 | * historic vi practice, but with mapping characters, you Just |
654 | * Never Know. |
655 | */ |
656 | KEY(key, 0){ if ((gcret = v_key(sp, 0, &ev, (0))) != GC_OK) return ( gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (key) = ev._u_event._e_ch.c; }; |
657 | |
658 | if (vp->key != key) { |
659 | usage: if (ismotion == NULL((void *)0)) |
660 | s = kp->usage; |
661 | else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP)((((&(((sp)))->opts[(((O_TILDEOP)))])->flags) & ((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_TILDEOP )))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_TILDEOP))) ].o_cur.val)) |
662 | s = tmotion.usage; |
663 | else |
664 | s = vikeys[ismotion->key].usage; |
665 | v_emsg(sp, s, VIM_USAGE); |
666 | return (GC_ERR); |
667 | } |
668 | } |
669 | /* Special case: 'z' command. */ |
670 | if (vp->key == 'z') { |
671 | KEY(vp->character, 0){ if ((gcret = v_key(sp, 0, &ev, (0))) != GC_OK) return ( gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (vp->character) = ev._u_event._e_ch.c; }; |
672 | if (isdigit(vp->character)) { |
673 | if (v_count(sp, vp->character, &vp->count2)) |
674 | return (GC_ERR); |
675 | F_SET(vp, VC_C2SET)(((vp)->flags) |= ((0x00001000))); |
676 | KEY(vp->character, 0){ if ((gcret = v_key(sp, 0, &ev, (0))) != GC_OK) return ( gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (vp->character) = ev._u_event._e_ch.c; }; |
677 | } |
678 | } |
679 | |
680 | /* |
681 | * Commands that have motion components can be doubled to |
682 | * imply the current line. |
683 | */ |
684 | if (ismotion != NULL((void *)0) && ismotion->key != key && !LF_ISSET(V_MOVE)((flags) & ((0x00400000)))) { |
685 | msgq(sp, M_ERR, "%s may not be used as a motion command", |
686 | KEY_NAME(sp, key)((unsigned char)(key) <= 254 ? (sp)->gp->cname[(unsigned char)(key)].name : v_key_name((sp), (key)))); |
687 | return (GC_ERR); |
688 | } |
689 | |
690 | /* Required character. */ |
691 | if (LF_ISSET(V_CHAR)((flags) & ((0x00020000)))) |
692 | KEY(vp->character, 0){ if ((gcret = v_key(sp, 0, &ev, (0))) != GC_OK) return ( gcret); if (ev._u_event._e_ch.value == K_ESCAPE) goto esc; if ((((&ev._u_event._e_ch)->flags) & ((0x02)))) *mappedp = 1; (vp->character) = ev._u_event._e_ch.c; }; |
693 | |
694 | /* Get any associated cursor word. */ |
695 | if (F_ISSET(kp, V_KEYW)(((kp)->flags) & ((0x00100000))) && v_keyword(sp)) |
696 | return (GC_ERR); |
697 | |
698 | return (GC_OK); |
699 | |
700 | esc: switch (cpart) { |
701 | case COMMANDMODE: |
702 | msgq(sp, M_BERR, "Already in command mode"); |
703 | return (GC_ERR_NOFLUSH); |
704 | case ISPARTIAL: |
705 | break; |
706 | case NOTPARTIAL: |
707 | (void)sp->gp->scr_bell(sp); |
708 | break; |
709 | } |
710 | return (GC_ERR); |
711 | } |
712 | |
713 | /* |
714 | * v_motion -- |
715 | * |
716 | * Get resulting motion mark. |
717 | */ |
718 | static int |
719 | v_motion(SCR *sp, VICMD *dm, VICMD *vp, int *mappedp) |
720 | { |
721 | VICMD motion; |
722 | size_t len; |
723 | u_long cnt; |
724 | u_int flags; |
725 | int tilde_reset, notused; |
726 | |
727 | /* |
728 | * If '.' command, use the dot motion, else get the motion command. |
729 | * Clear any line motion flags, the subsequent motion isn't always |
730 | * the same, i.e. "/aaa" may or may not be a line motion. |
731 | */ |
732 | if (F_ISSET(vp, VC_ISDOT)(((vp)->flags) & ((0x00002000)))) { |
733 | motion = *dm; |
734 | F_SET(&motion, VC_ISDOT)(((&motion)->flags) |= ((0x00002000))); |
735 | F_CLR(&motion, VM_COMMASK)(((&motion)->flags) &= ~((0x0000000f))); |
736 | } else { |
737 | memset(&motion, 0, sizeof(VICMD)); |
738 | if (v_cmd(sp, NULL((void *)0), &motion, vp, ¬used, mappedp) != GC_OK) |
739 | return (1); |
740 | } |
741 | |
742 | /* |
743 | * A count may be provided both to the command and to the motion, in |
744 | * which case the count is multiplicative. For example, "3y4y" is the |
745 | * same as "12yy". This count is provided to the motion command and |
746 | * not to the regular function. |
747 | */ |
748 | cnt = motion.count = F_ISSET(&motion, VC_C1SET)(((&motion)->flags) & ((0x00000800))) ? motion.count : 1; |
749 | if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800)))) { |
750 | motion.count *= vp->count; |
751 | F_SET(&motion, VC_C1SET)(((&motion)->flags) |= ((0x00000800))); |
752 | |
753 | /* |
754 | * Set flags to restore the original values of the command |
755 | * structure so dot commands can change the count values, |
756 | * e.g. "2dw" "3." deletes a total of five words. |
757 | */ |
758 | F_CLR(vp, VC_C1SET)(((vp)->flags) &= ~((0x00000800))); |
759 | F_SET(vp, VC_C1RESET)(((vp)->flags) |= ((0x00000400))); |
760 | } |
761 | |
762 | /* |
763 | * Some commands can be repeated to indicate the current line. In |
764 | * this case, or if the command is a "line command", set the flags |
765 | * appropriately. If not a doubled command, run the function to get |
766 | * the resulting mark. |
767 | */ |
768 | if (vp->key == motion.key) { |
769 | F_SET(vp, VM_LDOUBLE | VM_LMODE)(((vp)->flags) |= ((0x00000004 | 0x00000008))); |
770 | |
771 | /* Set the origin of the command. */ |
772 | vp->m_start.lno = sp->lno; |
773 | vp->m_start.cno = 0; |
774 | |
775 | /* |
776 | * Set the end of the command. |
777 | * |
778 | * If the current line is missing, i.e. the file is empty, |
779 | * historic vi permitted a "cc" or "!!" command to insert |
780 | * text. |
781 | */ |
782 | vp->m_stop.lno = sp->lno + motion.count - 1; |
783 | if (db_get(sp, vp->m_stop.lno, 0, NULL((void *)0), &len)) { |
784 | if (vp->m_stop.lno != 1 || |
785 | (vp->key != 'c' && vp->key != '!')) { |
786 | v_emsg(sp, NULL((void *)0), VIM_EMPTY); |
787 | return (1); |
788 | } |
789 | vp->m_stop.cno = 0; |
790 | } else |
791 | vp->m_stop.cno = len ? len - 1 : 0; |
792 | } else { |
793 | /* |
794 | * Motion commands change the underlying movement (*snarl*). |
795 | * For example, "l" is illegal at the end of a line, but "dl" |
796 | * is not. Set flags so the function knows the situation. |
797 | */ |
798 | motion.rkp = vp->kp; |
799 | |
800 | /* |
801 | * XXX |
802 | * Use yank instead of creating a new motion command, it's a |
803 | * lot easier for now. |
804 | */ |
805 | if (vp->kp == &tmotion) { |
806 | tilde_reset = 1; |
807 | vp->kp = &vikeys['y']; |
808 | } else |
809 | tilde_reset = 0; |
810 | |
811 | /* |
812 | * Copy the key flags into the local structure, except for the |
813 | * RCM flags -- the motion command will set the RCM flags in |
814 | * the vp structure if necessary. This means that the motion |
815 | * command is expected to determine where the cursor ends up! |
816 | * However, we save off the current RCM mask and restore it if |
817 | * it no RCM flags are set by the motion command, with a small |
818 | * modification. |
819 | * |
820 | * We replace the VM_RCM_SET flag with the VM_RCM flag. This |
821 | * is so that cursor movement doesn't set the relative position |
822 | * unless the motion command explicitly specified it. This |
823 | * appears to match historic practice, but I've never been able |
824 | * to develop a hard-and-fast rule. |
825 | */ |
826 | flags = F_ISSET(vp, VM_RCM_MASK)(((vp)->flags) & ((0x000001f0))); |
827 | if (LF_ISSET(VM_RCM_SET)((flags) & ((0x00000020)))) { |
828 | LF_SET(VM_RCM)((flags) |= ((0x00000010))); |
829 | LF_CLR(VM_RCM_SET)((flags) &= ~((0x00000020))); |
830 | } |
831 | F_CLR(vp, VM_RCM_MASK)(((vp)->flags) &= ~((0x000001f0))); |
832 | F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK)(((&motion)->flags) |= ((motion.kp->flags & ~0x000001f0 ))); |
833 | |
834 | /* |
835 | * Set the three cursor locations to the current cursor. This |
836 | * permits commands like 'j' and 'k', that are line oriented |
837 | * motions and have special cursor suck semantics when they are |
838 | * used as standalone commands, to ignore column positioning. |
839 | */ |
840 | motion.m_final.lno = |
841 | motion.m_stop.lno = motion.m_start.lno = sp->lno; |
842 | motion.m_final.cno = |
843 | motion.m_stop.cno = motion.m_start.cno = sp->cno; |
844 | |
845 | /* Run the function. */ |
846 | if ((motion.kp->func)(sp, &motion)) |
847 | return (1); |
848 | |
849 | /* |
850 | * If the current line is missing, i.e. the file is empty, |
851 | * historic vi allowed "c<motion>" or "!<motion>" to insert |
852 | * text. Otherwise fail -- most motion commands will have |
853 | * already failed, but some, e.g. G, succeed in empty files. |
854 | */ |
855 | if (!db_exist(sp, vp->m_stop.lno)) { |
856 | if (vp->m_stop.lno != 1 || |
857 | (vp->key != 'c' && vp->key != '!')) { |
858 | v_emsg(sp, NULL((void *)0), VIM_EMPTY); |
859 | return (1); |
860 | } |
861 | vp->m_stop.cno = 0; |
862 | } |
863 | |
864 | /* |
865 | * XXX |
866 | * See above. |
867 | */ |
868 | if (tilde_reset) |
869 | vp->kp = &tmotion; |
870 | |
871 | /* |
872 | * Copy cut buffer, line mode and cursor position information |
873 | * from the motion command structure, i.e. anything that the |
874 | * motion command can set for us. The commands can flag the |
875 | * movement as a line motion (see v_sentence) as well as set |
876 | * the VM_RCM_* flags explicitly. |
877 | */ |
878 | F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK))(((vp)->flags) |= (((((&motion)->flags) & ((0x0000000f | 0x000001f0)))))); |
879 | |
880 | /* |
881 | * If the motion command set no relative motion flags, use |
882 | * the (slightly) modified previous values. |
883 | */ |
884 | if (!F_ISSET(vp, VM_RCM_MASK)(((vp)->flags) & ((0x000001f0)))) |
885 | F_SET(vp, flags)(((vp)->flags) |= ((flags))); |
886 | |
887 | /* |
888 | * Commands can change behaviors based on the motion command |
889 | * used, for example, the ! command repeated the last bang |
890 | * command if N or n was used as the motion. |
891 | */ |
892 | vp->rkp = motion.kp; |
893 | |
894 | /* |
895 | * Motion commands can reset all of the cursor information. |
896 | * If the motion is in the reverse direction, switch the |
897 | * from and to MARK's so that it's in a forward direction. |
898 | * Motions are from the from MARK to the to MARK (inclusive). |
899 | */ |
900 | if (motion.m_start.lno > motion.m_stop.lno || |
901 | (motion.m_start.lno == motion.m_stop.lno && |
902 | motion.m_start.cno > motion.m_stop.cno)) { |
903 | vp->m_start = motion.m_stop; |
904 | vp->m_stop = motion.m_start; |
905 | } else { |
906 | vp->m_start = motion.m_start; |
907 | vp->m_stop = motion.m_stop; |
908 | } |
909 | vp->m_final = motion.m_final; |
910 | } |
911 | |
912 | /* |
913 | * If the command sets dot, save the motion structure. The motion |
914 | * count was changed above and needs to be reset, that's why this |
915 | * is done here, and not in the calling routine. |
916 | */ |
917 | if (F_ISSET(vp->kp, V_DOT)(((vp->kp)->flags) & ((0x00080000)))) { |
918 | *dm = motion; |
919 | dm->count = cnt; |
920 | } |
921 | return (0); |
922 | } |
923 | |
924 | /* |
925 | * v_init -- |
926 | * Initialize the vi screen. |
927 | */ |
928 | static int |
929 | v_init(SCR *sp) |
930 | { |
931 | GS *gp; |
932 | VI_PRIVATE *vip; |
933 | |
934 | gp = sp->gp; |
935 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); |
936 | |
937 | /* Switch into vi. */ |
938 | if (gp->scr_screen(sp, SC_VI0x00000002)) |
939 | return (1); |
940 | (void)gp->scr_attr(sp, SA_ALTERNATE, 1); |
941 | |
942 | F_CLR(sp, SC_EX | SC_SCR_EX)(((sp)->flags) &= ~((0x00000001 | 0x00000004))); |
943 | F_SET(sp, SC_VI)(((sp)->flags) |= ((0x00000002))); |
944 | |
945 | /* |
946 | * Initialize screen values. |
947 | * |
948 | * Small windows: see vs_refresh(), section 6a. |
949 | * |
950 | * Setup: |
951 | * t_minrows is the minimum rows to display |
952 | * t_maxrows is the maximum rows to display (rows - 1) |
953 | * t_rows is the rows currently being displayed |
954 | */ |
955 | sp->rows = vip->srows = O_VAL(sp, O_LINES)((((&((sp))->opts[((O_LINES))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_LINES))].o_cur .val].o_cur.val : ((sp))->opts[((O_LINES))].o_cur.val); |
956 | sp->cols = O_VAL(sp, O_COLUMNS)((((&((sp))->opts[((O_COLUMNS))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_COLUMNS))].o_cur .val].o_cur.val : ((sp))->opts[((O_COLUMNS))].o_cur.val); |
957 | sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW)((((&((sp))->opts[((O_WINDOW))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_WINDOW))].o_cur .val].o_cur.val : ((sp))->opts[((O_WINDOW))].o_cur.val); |
958 | if (sp->rows != 1) { |
959 | if (sp->t_rows > sp->rows - 1) { |
960 | sp->t_minrows = sp->t_rows = sp->rows - 1; |
961 | msgq(sp, M_INFO, |
962 | "Windows option value is too large, max is %u", |
963 | sp->t_rows); |
964 | } |
965 | sp->t_maxrows = sp->rows - 1; |
966 | } else |
967 | sp->t_maxrows = 1; |
968 | sp->woff = 0; |
969 | |
970 | /* Create a screen map. */ |
971 | CALLOC_RET(sp, HMAP, SIZE_HMAP(sp), sizeof(SMAP)){ if ((((((VI_PRIVATE *)((sp)->vi_private))->h_smap)) = calloc(((((VI_PRIVATE *)((sp)->vi_private))->srows + 1 )), (sizeof(SMAP)))) == ((void *)0)) { msgq((sp), M_SYSERR, ( (void *)0)); return (1); } }; |
972 | TMAP(((VI_PRIVATE *)((sp)->vi_private))->t_smap) = HMAP(((VI_PRIVATE *)((sp)->vi_private))->h_smap) + (sp->t_rows - 1); |
973 | HMAP(((VI_PRIVATE *)((sp)->vi_private))->h_smap)->lno = sp->lno; |
974 | HMAP(((VI_PRIVATE *)((sp)->vi_private))->h_smap)->coff = 0; |
975 | HMAP(((VI_PRIVATE *)((sp)->vi_private))->h_smap)->soff = 1; |
976 | |
977 | /* |
978 | * Fill the screen map from scratch -- try and center the line. That |
979 | * way if we're starting with a file we've seen before, we'll put the |
980 | * line in the middle, otherwise, it won't work and we'll end up with |
981 | * the line at the top. |
982 | */ |
983 | F_CLR(sp, SC_SCR_TOP)(((sp)->flags) &= ~((0x00000100))); |
984 | F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER)(((sp)->flags) |= ((0x00000020 | 0x00000080))); |
985 | |
986 | /* Invalidate the cursor. */ |
987 | F_SET(vip, VIP_CUR_INVALID)(((vip)->flags) |= ((0x0001))); |
988 | |
989 | /* Paint the screen image from scratch. */ |
990 | F_SET(vip, VIP_N_EX_PAINT)(((vip)->flags) |= ((0x0004))); |
991 | |
992 | return (0); |
993 | } |
994 | |
995 | /* |
996 | * v_dtoh -- |
997 | * Move all but the current screen to the hidden queue. |
998 | */ |
999 | static void |
1000 | v_dtoh(SCR *sp) |
1001 | { |
1002 | GS *gp; |
1003 | SCR *tsp; |
1004 | int hidden; |
1005 | |
1006 | /* Move all screens to the hidden queue, tossing screen maps. */ |
1007 | hidden = 0; |
1008 | gp = sp->gp; |
1009 | while ((tsp = TAILQ_FIRST(&gp->dq)((&gp->dq)->tqh_first))) { |
1010 | free(_HMAP(tsp)(((VI_PRIVATE *)((tsp)->vi_private))->h_smap)); |
1011 | _HMAP(tsp)(((VI_PRIVATE *)((tsp)->vi_private))->h_smap) = NULL((void *)0); |
1012 | TAILQ_REMOVE(&gp->dq, tsp, q)do { if (((tsp)->q.tqe_next) != ((void *)0)) (tsp)->q.tqe_next ->q.tqe_prev = (tsp)->q.tqe_prev; else (&gp->dq) ->tqh_last = (tsp)->q.tqe_prev; *(tsp)->q.tqe_prev = (tsp)->q.tqe_next; ; ; } while (0); |
1013 | TAILQ_INSERT_TAIL(&gp->hq, tsp, q)do { (tsp)->q.tqe_next = ((void *)0); (tsp)->q.tqe_prev = (&gp->hq)->tqh_last; *(&gp->hq)->tqh_last = (tsp); (&gp->hq)->tqh_last = &(tsp)->q.tqe_next ; } while (0); |
1014 | ++hidden; |
1015 | } |
1016 | |
1017 | /* Move current screen back to the display queue. */ |
1018 | TAILQ_REMOVE(&gp->hq, sp, q)do { if (((sp)->q.tqe_next) != ((void *)0)) (sp)->q.tqe_next ->q.tqe_prev = (sp)->q.tqe_prev; else (&gp->hq)-> tqh_last = (sp)->q.tqe_prev; *(sp)->q.tqe_prev = (sp)-> q.tqe_next; ; ; } while (0); |
1019 | TAILQ_INSERT_TAIL(&gp->dq, sp, q)do { (sp)->q.tqe_next = ((void *)0); (sp)->q.tqe_prev = (&gp->dq)->tqh_last; *(&gp->dq)->tqh_last = (sp); (&gp->dq)->tqh_last = &(sp)->q.tqe_next ; } while (0); |
1020 | |
1021 | /* |
1022 | * XXX |
1023 | * Don't bother internationalizing this message, it's going to |
1024 | * go away as soon as we have one-line screens. --TK |
1025 | */ |
1026 | if (hidden > 1) |
1027 | msgq(sp, M_INFO, |
1028 | "%d screens backgrounded; use :display to list them", |
1029 | hidden - 1); |
1030 | } |
1031 | |
1032 | /* |
1033 | * v_keyword -- |
1034 | * Get the word (or non-word) the cursor is on. |
1035 | */ |
1036 | static int |
1037 | v_keyword(SCR *sp) |
1038 | { |
1039 | VI_PRIVATE *vip; |
1040 | size_t beg, end, len; |
1041 | int moved, state; |
1042 | char *p; |
1043 | |
1044 | if (db_get(sp, sp->lno, DBG_FATAL0x001, &p, &len)) |
1045 | return (1); |
1046 | |
1047 | /* |
1048 | * !!! |
1049 | * Historically, tag commands skipped over any leading whitespace |
1050 | * characters. Make this true in general when using cursor words. |
1051 | * If movement, getting a cursor word implies moving the cursor to |
1052 | * its beginning. Refresh now. |
1053 | * |
1054 | * !!! |
1055 | * Find the beginning/end of the keyword. Keywords are currently |
1056 | * used for cursor-word searching and for tags. Historical vi |
1057 | * only used the word in a tag search from the cursor to the end |
1058 | * of the word, i.e. if the cursor was on the 'b' in " abc ", the |
1059 | * tag was "bc". For consistency, we make cursor word searches |
1060 | * follow the same rule. |
1061 | */ |
1062 | for (moved = 0, |
1063 | beg = sp->cno; beg < len && isspace(p[beg]); moved = 1, ++beg); |
1064 | if (beg >= len) { |
1065 | msgq(sp, M_BERR, "Cursor not in a word"); |
1066 | return (1); |
1067 | } |
1068 | if (moved) { |
1069 | sp->cno = beg; |
1070 | (void)vs_refresh(sp, 0); |
1071 | } |
1072 | |
1073 | /* Find the end of the word. */ |
1074 | for (state = inword(p[beg])(isalnum(p[beg]) || (p[beg]) == '_'), |
1075 | end = beg; ++end < len && state == inword(p[end])(isalnum(p[end]) || (p[end]) == '_');); |
1076 | |
1077 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); |
1078 | len = (end - beg); |
1079 | BINC_RET(sp, vip->keyw, vip->klen, len){ void *L__bincp; if ((len) > (vip->klen)) { if ((L__bincp = binc((sp), (vip->keyw), &(vip->klen), (len))) == ((void *)0)) return (1); (vip->keyw) = L__bincp; } }; |
1080 | memmove(vip->keyw, p + beg, len); |
1081 | vip->keyw[len] = '\0'; /* XXX */ |
1082 | return (0); |
1083 | } |
1084 | |
1085 | /* |
1086 | * v_alias -- |
1087 | * Check for a command alias. |
1088 | */ |
1089 | static VIKEYS const * |
1090 | v_alias(SCR *sp, VICMD *vp, VIKEYS const *kp) |
1091 | { |
1092 | CHAR_T push; |
1093 | |
1094 | switch (vp->key) { |
1095 | case 'C': /* C -> c$ */ |
1096 | push = '$'; |
1097 | vp->key = 'c'; |
1098 | break; |
1099 | case 'D': /* D -> d$ */ |
1100 | push = '$'; |
1101 | vp->key = 'd'; |
1102 | break; |
1103 | case 'S': /* S -> c_ */ |
1104 | push = '_'; |
1105 | vp->key = 'c'; |
1106 | break; |
1107 | case 'Y': /* Y -> y_ */ |
1108 | push = '_'; |
1109 | vp->key = 'y'; |
1110 | break; |
1111 | default: |
1112 | return (kp); |
1113 | } |
1114 | return (v_event_push(sp, |
1115 | NULL((void *)0), &push, 1, CH_NOMAP0x04 | CH_QUOTED0x08) ? NULL((void *)0) : &vikeys[vp->key]); |
1116 | } |
1117 | |
1118 | /* |
1119 | * v_count -- |
1120 | * Return the next count. |
1121 | */ |
1122 | static int |
1123 | v_count(SCR *sp, CHAR_T fkey, u_long *countp) |
1124 | { |
1125 | EVENT ev; |
1126 | u_long count, tc; |
1127 | |
1128 | ev.e_c_u_event._e_ch.c = fkey; |
1129 | count = tc = 0; |
Although the value stored to 'tc' is used in the enclosing expression, the value is never actually read from 'tc' | |
1130 | do { |
1131 | /* |
1132 | * XXX |
1133 | * Assume that overflow results in a smaller number. |
1134 | */ |
1135 | tc = count * 10 + ev.e_c_u_event._e_ch.c - '0'; |
1136 | if (count > tc) { |
1137 | /* Toss to the next non-digit. */ |
1138 | do { |
1139 | if (v_key(sp, 0, &ev, |
1140 | EC_MAPCOMMAND0x002 | EC_MAPNODIGIT0x008) != GC_OK) |
1141 | return (1); |
1142 | } while (isdigit(ev.e_c_u_event._e_ch.c)); |
1143 | msgq(sp, M_ERR, |
1144 | "Number larger than %lu", ULONG_MAX0xffffffffffffffffUL); |
1145 | return (1); |
1146 | } |
1147 | count = tc; |
1148 | if (v_key(sp, 0, &ev, EC_MAPCOMMAND0x002 | EC_MAPNODIGIT0x008) != GC_OK) |
1149 | return (1); |
1150 | } while (isdigit(ev.e_c_u_event._e_ch.c)); |
1151 | *countp = count; |
1152 | return (0); |
1153 | } |
1154 | |
1155 | /* |
1156 | * v_key -- |
1157 | * Return the next event. |
1158 | */ |
1159 | static gcret_t |
1160 | v_key(SCR *sp, int command_events, EVENT *evp, u_int32_t ec_flags) |
1161 | { |
1162 | u_int32_t quote; |
1163 | |
1164 | for (quote = 0;;) { |
1165 | if (v_event_get(sp, evp, 0, ec_flags | quote)) |
1166 | return (GC_FATAL); |
1167 | quote = 0; |
1168 | |
1169 | switch (evp->e_event) { |
1170 | case E_CHARACTER: |
1171 | /* |
1172 | * !!! |
1173 | * Historically, ^V was ignored in the command stream, |
1174 | * although it had a useful side-effect of interrupting |
1175 | * mappings. Adding a quoting bit to the call probably |
1176 | * extends historic practice, but it feels right. |
1177 | */ |
1178 | if (evp->e_value_u_event._e_ch.value == K_VLNEXT) { |
1179 | quote = EC_QUOTED0x010; |
1180 | break; |
1181 | } |
1182 | return (GC_OK); |
1183 | case E_ERR: |
1184 | case E_EOF: |
1185 | return (GC_FATAL); |
1186 | case E_INTERRUPT: |
1187 | /* |
1188 | * !!! |
1189 | * Historically, vi beeped on command level interrupts. |
1190 | * |
1191 | * Historically, vi exited to ex mode if no file was |
1192 | * named on the command line, and two interrupts were |
1193 | * generated in a row. (Just figured you might want |
1194 | * to know that.) |
1195 | */ |
1196 | (void)sp->gp->scr_bell(sp); |
1197 | return (GC_INTERRUPT); |
1198 | case E_REPAINT: |
1199 | if (vs_repaint(sp, evp)) |
1200 | return (GC_FATAL); |
1201 | break; |
1202 | case E_WRESIZE: |
1203 | return (GC_ERR); |
1204 | case E_QUIT: |
1205 | case E_WRITE: |
1206 | if (command_events) |
1207 | return (GC_EVENT); |
1208 | /* FALLTHROUGH */ |
1209 | default: |
1210 | v_event_err(sp, evp); |
1211 | return (GC_ERR); |
1212 | } |
1213 | } |
1214 | /* NOTREACHED */ |
1215 | } |
1216 | |
1217 | #if defined(DEBUG) && defined(COMLOG) |
1218 | /* |
1219 | * v_comlog -- |
1220 | * Log the contents of the command structure. |
1221 | */ |
1222 | static void |
1223 | v_comlog(SCR *sp, VICMD *vp) |
1224 | { |
1225 | TRACE(sp, "vcmd: %c", vp->key); |
1226 | if (F_ISSET(vp, VC_BUFFER)(((vp)->flags) & ((0x00000200)))) |
1227 | TRACE(sp, " buffer: %c", vp->buffer); |
1228 | if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800)))) |
1229 | TRACE(sp, " c1: %lu", vp->count); |
1230 | if (F_ISSET(vp, VC_C2SET)(((vp)->flags) & ((0x00001000)))) |
1231 | TRACE(sp, " c2: %lu", vp->count2); |
1232 | TRACE(sp, " flags: 0x%x\n", vp->flags); |
1233 | } |
1234 | #endif |