Bug Summary

File:src/usr.bin/vi/build/../vi/vi.c
Warning:line 1125, column 10
Although the value stored to 'tc' is used in the enclosing expression, the value is never actually read from 'tc'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name vi.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/vi/build/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/vi/build -I /usr/src/usr.bin/vi/build/../include -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/vi/build/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/vi/build/../vi/vi.c
1/* $OpenBSD: vi.c,v 1.22 2019/01/24 15:09:41 millert 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
30typedef enum {
31 GC_ERR, GC_ERR_NOFLUSH, GC_EVENT, GC_FATAL, GC_INTERRUPT, GC_OK
32} gcret_t;
33
34static VIKEYS const
35 *v_alias(SCR *, VICMD *, VIKEYS const *);
36static gcret_t v_cmd(SCR *, VICMD *, VICMD *, VICMD *, int *, int *);
37static int v_count(SCR *, CHAR_T, u_long *);
38static void v_dtoh(SCR *);
39static int v_init(SCR *);
40static gcret_t v_key(SCR *, int, EVENT *, u_int32_t);
41static int v_keyword(SCR *);
42static int v_motion(SCR *, VICMD *, VICMD *, int *);
43
44#if defined(DEBUG) && defined(COMLOG)
45static 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 */
62int
63vi(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. */
232ex_continue: if (vp->kp->func(sp, vp))
233 goto err;
234gc_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) {
354err: 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 */
363gc_err_noflush: if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get
((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)->
flags) & ((0x0004)))))
) {
364intr: 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 /* If leaving vi, return to the main editor loop. */
404 if (F_ISSET(gp, G_SRESTART)(((gp)->flags) & ((0x0080))) || F_ISSET(sp, SC_EX)(((sp)->flags) & ((0x00000001)))) {
405 *spp = sp;
406 v_dtoh(sp);
407 break;
408 }
409 }
410 if (0)
411ret: rval = 1;
412 return (rval);
413}
414
415#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; }
{ \
416 if ((gcret = v_key(sp, 0, &ev, (ec_flags))) != GC_OK) \
417 return (gcret); \
418 if (ev.e_value_u_event._e_ch.value == K_ESCAPE) \
419 goto esc; \
420 if (F_ISSET(&ev.e_ch, CH_MAPPED)(((&ev._u_event._e_ch)->flags) & ((0x02)))) \
421 *mappedp = 1; \
422 (key) = ev.e_c_u_event._e_ch.c; \
423}
424
425/*
426 * The O_TILDEOP option makes the ~ command take a motion instead
427 * of a straight count. This is the replacement structure we use
428 * instead of the one currently in the VIKEYS table.
429 *
430 * XXX
431 * This should probably be deleted -- it's not all that useful, and
432 * we get help messages wrong.
433 */
434VIKEYS const tmotion = {
435 v_mulcase, V_CNT0x00040000|V_DOT0x00080000|V_MOTION0x00200000|VM_RCM_SET0x00000020,
436 "[count]~[count]motion",
437 " ~ change case to motion"
438};
439
440/*
441 * v_cmd --
442 *
443 * The command structure for vi is less complex than ex (and don't think
444 * I'm not grateful!) The command syntax is:
445 *
446 * [count] [buffer] [count] key [[motion] | [buffer] [character]]
447 *
448 * and there are several special cases. The motion value is itself a vi
449 * command, with the syntax:
450 *
451 * [count] key [character]
452 */
453static gcret_t
454v_cmd(SCR *sp, VICMD *dp, VICMD *vp, VICMD *ismotion, int *comcountp,
455 int *mappedp)
456{
457 enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart;
458 EVENT ev;
459 VIKEYS const *kp;
460 gcret_t gcret;
461 u_int flags;
462 CHAR_T key;
463 char *s;
464
465 /*
466 * Get a key.
467 *
468 * <escape> cancels partial commands, i.e. a command where at least
469 * one non-numeric character has been entered. Otherwise, it beeps
470 * the terminal.
471 *
472 * !!!
473 * POSIX 1003.2-1992 explicitly disallows cancelling commands where
474 * all that's been entered is a number, requiring that the terminal
475 * be alerted.
476 */
477 cpart = ismotion == NULL((void *)0) ? COMMANDMODE : ISPARTIAL;
478 if ((gcret =
479 v_key(sp, ismotion == NULL((void *)0), &ev, EC_MAPCOMMAND0x002)) != GC_OK) {
480 if (gcret == GC_EVENT)
481 vp->ev = ev;
482 return (gcret);
483 }
484 if (ev.e_value_u_event._e_ch.value == K_ESCAPE)
485 goto esc;
486 if (F_ISSET(&ev.e_ch, CH_MAPPED)(((&ev._u_event._e_ch)->flags) & ((0x02))))
487 *mappedp = 1;
488 key = ev.e_c_u_event._e_ch.c;
489
490 if (ismotion == NULL((void *)0))
491 cpart = NOTPARTIAL;
492
493 /* Pick up optional buffer. */
494 if (key == '"') {
495 cpart = ISPARTIAL;
496 if (ismotion != NULL((void *)0)) {
497 v_emsg(sp, NULL((void *)0), VIM_COMBUF);
498 return (GC_ERR);
499 }
500 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; }
;
501 F_SET(vp, VC_BUFFER)(((vp)->flags) |= ((0x00000200)));
502
503 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; }
;
504 }
505
506 /*
507 * Pick up optional count, where a leading 0 is not a count,
508 * it's a command.
509 */
510 if (isdigit(key) && key != '0') {
511 if (v_count(sp, key, &vp->count))
512 return (GC_ERR);
513 F_SET(vp, VC_C1SET)(((vp)->flags) |= ((0x00000800)));
514 *comcountp = 1;
515
516 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; }
;
517 } else
518 *comcountp = 0;
519
520 /* Pick up optional buffer. */
521 if (key == '"') {
522 cpart = ISPARTIAL;
523 if (F_ISSET(vp, VC_BUFFER)(((vp)->flags) & ((0x00000200)))) {
524 msgq(sp, M_ERR, "Only one buffer may be specified");
525 return (GC_ERR);
526 }
527 if (ismotion != NULL((void *)0)) {
528 v_emsg(sp, NULL((void *)0), VIM_COMBUF);
529 return (GC_ERR);
530 }
531 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; }
;
532 F_SET(vp, VC_BUFFER)(((vp)->flags) |= ((0x00000200)));
533
534 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; }
;
535 }
536
537 /* Check for an OOB command key. */
538 cpart = ISPARTIAL;
539 if (key > MAXVIKEY126) {
540 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);
541 return (GC_ERR);
542 }
543 kp = &vikeys[vp->key = key];
544
545 /*
546 * !!!
547 * Historically, D accepted and then ignored a count. Match it.
548 */
549 if (vp->key == 'D' && F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800)))) {
550 *comcountp = 0;
551 vp->count = 0;
552 F_CLR(vp, VC_C1SET)(((vp)->flags) &= ~((0x00000800)));
553 }
554
555 /* Check for command aliases. */
556 if (kp->func == NULL((void *)0) && (kp = v_alias(sp, vp, kp)) == NULL((void *)0))
557 return (GC_ERR);
558
559 /* The tildeop option makes the ~ command take a motion. */
560 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)
)
561 kp = &tmotion;
562
563 vp->kp = kp;
564
565 /*
566 * Find the command. The only legal command with no underlying
567 * function is dot. It's historic practice that <escape> doesn't
568 * just erase the preceding number, it beeps the terminal as well.
569 * It's a common problem, so just beep the terminal unless verbose
570 * was set.
571 */
572 if (kp->func == NULL((void *)0)) {
573 if (key != '.') {
574 v_emsg(sp, KEY_NAME(sp, key)((unsigned char)(key) <= 254 ? (sp)->gp->cname[(unsigned
char)(key)].name : v_key_name((sp), (key)))
,
575 ev.e_value_u_event._e_ch.value == K_ESCAPE ? VIM_NOCOM_B : VIM_NOCOM);
576 return (GC_ERR);
577 }
578
579 /* If called for a motion command, stop now. */
580 if (dp == NULL((void *)0))
581 goto usage;
582
583 /*
584 * !!!
585 * If a '.' is immediately entered after an undo command, we
586 * replay the log instead of redoing the last command. This
587 * is necessary because 'u' can't set the dot command -- see
588 * vi/v_undo.c:v_undo for details.
589 */
590 if (VIP(sp)((VI_PRIVATE *)((sp)->vi_private))->u_ccnt == sp->ccnt) {
591 vp->kp = &vikeys['u'];
592 F_SET(vp, VC_ISDOT)(((vp)->flags) |= ((0x00002000)));
593 return (GC_OK);
594 }
595
596 /* Otherwise, a repeatable command must have been executed. */
597 if (!F_ISSET(dp, VC_ISDOT)(((dp)->flags) & ((0x00002000)))) {
598 msgq(sp, M_ERR, "No command to repeat");
599 return (GC_ERR);
600 }
601
602 /* Set new count/buffer, if any, and return. */
603 if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800)))) {
604 F_SET(dp, VC_C1SET)(((dp)->flags) |= ((0x00000800)));
605 dp->count = vp->count;
606 }
607 if (F_ISSET(vp, VC_BUFFER)(((vp)->flags) & ((0x00000200))))
608 dp->buffer = vp->buffer;
609
610 *vp = *dp;
611 return (GC_OK);
612 }
613
614 /* Set the flags based on the command flags. */
615 flags = kp->flags;
616
617 /* Check for illegal count. */
618 if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800))) && !LF_ISSET(V_CNT)((flags) & ((0x00040000))))
619 goto usage;
620
621 /* Illegal motion command. */
622 if (ismotion == NULL((void *)0)) {
623 /* Illegal buffer. */
624 if (!LF_ISSET(V_OBUF)((flags) & ((0x00800000))) && F_ISSET(vp, VC_BUFFER)(((vp)->flags) & ((0x00000200))))
625 goto usage;
626
627 /* Required buffer. */
628 if (LF_ISSET(V_RBUF)((flags) & ((0x01000000)))) {
629 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; }
;
630 F_SET(vp, VC_BUFFER)(((vp)->flags) |= ((0x00000200)));
631 }
632 }
633
634 /*
635 * Special case: '[', ']' and 'Z' commands. Doesn't the fact that
636 * the *single* characters don't mean anything but the *doubled*
637 * characters do, just frost your shorts?
638 */
639 if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
640 /*
641 * Historically, half entered [[, ]] or Z commands weren't
642 * cancelled by <escape>, the terminal was beeped instead.
643 * POSIX.2-1992 probably didn't notice, and requires that
644 * they be cancelled instead of beeping. Seems fine to me.
645 *
646 * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular
647 * vi meta-character, and we don't want the user to wait while
648 * we time out a possible mapping. This *appears* to match
649 * historic vi practice, but with mapping characters, you Just
650 * Never Know.
651 */
652 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; }
;
653
654 if (vp->key != key) {
655usage: if (ismotion == NULL((void *)0))
656 s = kp->usage;
657 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)
)
658 s = tmotion.usage;
659 else
660 s = vikeys[ismotion->key].usage;
661 v_emsg(sp, s, VIM_USAGE);
662 return (GC_ERR);
663 }
664 }
665 /* Special case: 'z' command. */
666 if (vp->key == 'z') {
667 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; }
;
668 if (isdigit(vp->character)) {
669 if (v_count(sp, vp->character, &vp->count2))
670 return (GC_ERR);
671 F_SET(vp, VC_C2SET)(((vp)->flags) |= ((0x00001000)));
672 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; }
;
673 }
674 }
675
676 /*
677 * Commands that have motion components can be doubled to
678 * imply the current line.
679 */
680 if (ismotion != NULL((void *)0) && ismotion->key != key && !LF_ISSET(V_MOVE)((flags) & ((0x00400000)))) {
681 msgq(sp, M_ERR, "%s may not be used as a motion command",
682 KEY_NAME(sp, key)((unsigned char)(key) <= 254 ? (sp)->gp->cname[(unsigned
char)(key)].name : v_key_name((sp), (key)))
);
683 return (GC_ERR);
684 }
685
686 /* Required character. */
687 if (LF_ISSET(V_CHAR)((flags) & ((0x00020000))))
688 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; }
;
689
690 /* Get any associated cursor word. */
691 if (F_ISSET(kp, V_KEYW)(((kp)->flags) & ((0x00100000))) && v_keyword(sp))
692 return (GC_ERR);
693
694 return (GC_OK);
695
696esc: switch (cpart) {
697 case COMMANDMODE:
698 msgq(sp, M_BERR, "Already in command mode");
699 return (GC_ERR_NOFLUSH);
700 case ISPARTIAL:
701 break;
702 case NOTPARTIAL:
703 (void)sp->gp->scr_bell(sp);
704 break;
705 }
706 return (GC_ERR);
707}
708
709/*
710 * v_motion --
711 *
712 * Get resulting motion mark.
713 */
714static int
715v_motion(SCR *sp, VICMD *dm, VICMD *vp, int *mappedp)
716{
717 VICMD motion;
718 size_t len;
719 u_long cnt;
720 u_int flags;
721 int tilde_reset, notused;
722
723 /*
724 * If '.' command, use the dot motion, else get the motion command.
725 * Clear any line motion flags, the subsequent motion isn't always
726 * the same, i.e. "/aaa" may or may not be a line motion.
727 */
728 if (F_ISSET(vp, VC_ISDOT)(((vp)->flags) & ((0x00002000)))) {
729 motion = *dm;
730 F_SET(&motion, VC_ISDOT)(((&motion)->flags) |= ((0x00002000)));
731 F_CLR(&motion, VM_COMMASK)(((&motion)->flags) &= ~((0x0000000f)));
732 } else {
733 memset(&motion, 0, sizeof(VICMD));
734 if (v_cmd(sp, NULL((void *)0), &motion, vp, &notused, mappedp) != GC_OK)
735 return (1);
736 }
737
738 /*
739 * A count may be provided both to the command and to the motion, in
740 * which case the count is multiplicative. For example, "3y4y" is the
741 * same as "12yy". This count is provided to the motion command and
742 * not to the regular function.
743 */
744 cnt = motion.count = F_ISSET(&motion, VC_C1SET)(((&motion)->flags) & ((0x00000800))) ? motion.count : 1;
745 if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800)))) {
746 motion.count *= vp->count;
747 F_SET(&motion, VC_C1SET)(((&motion)->flags) |= ((0x00000800)));
748
749 /*
750 * Set flags to restore the original values of the command
751 * structure so dot commands can change the count values,
752 * e.g. "2dw" "3." deletes a total of five words.
753 */
754 F_CLR(vp, VC_C1SET)(((vp)->flags) &= ~((0x00000800)));
755 F_SET(vp, VC_C1RESET)(((vp)->flags) |= ((0x00000400)));
756 }
757
758 /*
759 * Some commands can be repeated to indicate the current line. In
760 * this case, or if the command is a "line command", set the flags
761 * appropriately. If not a doubled command, run the function to get
762 * the resulting mark.
763 */
764 if (vp->key == motion.key) {
765 F_SET(vp, VM_LDOUBLE | VM_LMODE)(((vp)->flags) |= ((0x00000004 | 0x00000008)));
766
767 /* Set the origin of the command. */
768 vp->m_start.lno = sp->lno;
769 vp->m_start.cno = 0;
770
771 /*
772 * Set the end of the command.
773 *
774 * If the current line is missing, i.e. the file is empty,
775 * historic vi permitted a "cc" or "!!" command to insert
776 * text.
777 */
778 vp->m_stop.lno = sp->lno + motion.count - 1;
779 if (db_get(sp, vp->m_stop.lno, 0, NULL((void *)0), &len)) {
780 if (vp->m_stop.lno != 1 ||
781 (vp->key != 'c' && vp->key != '!')) {
782 v_emsg(sp, NULL((void *)0), VIM_EMPTY);
783 return (1);
784 }
785 vp->m_stop.cno = 0;
786 } else
787 vp->m_stop.cno = len ? len - 1 : 0;
788 } else {
789 /*
790 * Motion commands change the underlying movement (*snarl*).
791 * For example, "l" is illegal at the end of a line, but "dl"
792 * is not. Set flags so the function knows the situation.
793 */
794 motion.rkp = vp->kp;
795
796 /*
797 * XXX
798 * Use yank instead of creating a new motion command, it's a
799 * lot easier for now.
800 */
801 if (vp->kp == &tmotion) {
802 tilde_reset = 1;
803 vp->kp = &vikeys['y'];
804 } else
805 tilde_reset = 0;
806
807 /*
808 * Copy the key flags into the local structure, except for the
809 * RCM flags -- the motion command will set the RCM flags in
810 * the vp structure if necessary. This means that the motion
811 * command is expected to determine where the cursor ends up!
812 * However, we save off the current RCM mask and restore it if
813 * it no RCM flags are set by the motion command, with a small
814 * modification.
815 *
816 * We replace the VM_RCM_SET flag with the VM_RCM flag. This
817 * is so that cursor movement doesn't set the relative position
818 * unless the motion command explicitly specified it. This
819 * appears to match historic practice, but I've never been able
820 * to develop a hard-and-fast rule.
821 */
822 flags = F_ISSET(vp, VM_RCM_MASK)(((vp)->flags) & ((0x000001f0)));
823 if (LF_ISSET(VM_RCM_SET)((flags) & ((0x00000020)))) {
824 LF_SET(VM_RCM)((flags) |= ((0x00000010)));
825 LF_CLR(VM_RCM_SET)((flags) &= ~((0x00000020)));
826 }
827 F_CLR(vp, VM_RCM_MASK)(((vp)->flags) &= ~((0x000001f0)));
828 F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK)(((&motion)->flags) |= ((motion.kp->flags & ~0x000001f0
)))
;
829
830 /*
831 * Set the three cursor locations to the current cursor. This
832 * permits commands like 'j' and 'k', that are line oriented
833 * motions and have special cursor suck semantics when they are
834 * used as standalone commands, to ignore column positioning.
835 */
836 motion.m_final.lno =
837 motion.m_stop.lno = motion.m_start.lno = sp->lno;
838 motion.m_final.cno =
839 motion.m_stop.cno = motion.m_start.cno = sp->cno;
840
841 /* Run the function. */
842 if ((motion.kp->func)(sp, &motion))
843 return (1);
844
845 /*
846 * If the current line is missing, i.e. the file is empty,
847 * historic vi allowed "c<motion>" or "!<motion>" to insert
848 * text. Otherwise fail -- most motion commands will have
849 * already failed, but some, e.g. G, succeed in empty files.
850 */
851 if (!db_exist(sp, vp->m_stop.lno)) {
852 if (vp->m_stop.lno != 1 ||
853 (vp->key != 'c' && vp->key != '!')) {
854 v_emsg(sp, NULL((void *)0), VIM_EMPTY);
855 return (1);
856 }
857 vp->m_stop.cno = 0;
858 }
859
860 /*
861 * XXX
862 * See above.
863 */
864 if (tilde_reset)
865 vp->kp = &tmotion;
866
867 /*
868 * Copy cut buffer, line mode and cursor position information
869 * from the motion command structure, i.e. anything that the
870 * motion command can set for us. The commands can flag the
871 * movement as a line motion (see v_sentence) as well as set
872 * the VM_RCM_* flags explicitly.
873 */
874 F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK))(((vp)->flags) |= (((((&motion)->flags) & ((0x0000000f
| 0x000001f0))))))
;
875
876 /*
877 * If the motion command set no relative motion flags, use
878 * the (slightly) modified previous values.
879 */
880 if (!F_ISSET(vp, VM_RCM_MASK)(((vp)->flags) & ((0x000001f0))))
881 F_SET(vp, flags)(((vp)->flags) |= ((flags)));
882
883 /*
884 * Commands can change behaviors based on the motion command
885 * used, for example, the ! command repeated the last bang
886 * command if N or n was used as the motion.
887 */
888 vp->rkp = motion.kp;
889
890 /*
891 * Motion commands can reset all of the cursor information.
892 * If the motion is in the reverse direction, switch the
893 * from and to MARK's so that it's in a forward direction.
894 * Motions are from the from MARK to the to MARK (inclusive).
895 */
896 if (motion.m_start.lno > motion.m_stop.lno ||
897 (motion.m_start.lno == motion.m_stop.lno &&
898 motion.m_start.cno > motion.m_stop.cno)) {
899 vp->m_start = motion.m_stop;
900 vp->m_stop = motion.m_start;
901 } else {
902 vp->m_start = motion.m_start;
903 vp->m_stop = motion.m_stop;
904 }
905 vp->m_final = motion.m_final;
906 }
907
908 /*
909 * If the command sets dot, save the motion structure. The motion
910 * count was changed above and needs to be reset, that's why this
911 * is done here, and not in the calling routine.
912 */
913 if (F_ISSET(vp->kp, V_DOT)(((vp->kp)->flags) & ((0x00080000)))) {
914 *dm = motion;
915 dm->count = cnt;
916 }
917 return (0);
918}
919
920/*
921 * v_init --
922 * Initialize the vi screen.
923 */
924static int
925v_init(SCR *sp)
926{
927 GS *gp;
928 VI_PRIVATE *vip;
929
930 gp = sp->gp;
931 vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private));
932
933 /* Switch into vi. */
934 if (gp->scr_screen(sp, SC_VI0x00000002))
935 return (1);
936 (void)gp->scr_attr(sp, SA_ALTERNATE, 1);
937
938 F_CLR(sp, SC_EX | SC_SCR_EX)(((sp)->flags) &= ~((0x00000001 | 0x00000004)));
939 F_SET(sp, SC_VI)(((sp)->flags) |= ((0x00000002)));
940
941 /*
942 * Initialize screen values.
943 *
944 * Small windows: see vs_refresh(), section 6a.
945 *
946 * Setup:
947 * t_minrows is the minimum rows to display
948 * t_maxrows is the maximum rows to display (rows - 1)
949 * t_rows is the rows currently being displayed
950 */
951 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)
;
952 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)
;
953 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)
;
954 if (sp->rows != 1) {
955 if (sp->t_rows > sp->rows - 1) {
956 sp->t_minrows = sp->t_rows = sp->rows - 1;
957 msgq(sp, M_INFO,
958 "Windows option value is too large, max is %u",
959 sp->t_rows);
960 }
961 sp->t_maxrows = sp->rows - 1;
962 } else
963 sp->t_maxrows = 1;
964 sp->woff = 0;
965
966 /* Create a screen map. */
967 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); } }
;
968 TMAP(((VI_PRIVATE *)((sp)->vi_private))->t_smap) = HMAP(((VI_PRIVATE *)((sp)->vi_private))->h_smap) + (sp->t_rows - 1);
969 HMAP(((VI_PRIVATE *)((sp)->vi_private))->h_smap)->lno = sp->lno;
970 HMAP(((VI_PRIVATE *)((sp)->vi_private))->h_smap)->coff = 0;
971 HMAP(((VI_PRIVATE *)((sp)->vi_private))->h_smap)->soff = 1;
972
973 /*
974 * Fill the screen map from scratch -- try and center the line. That
975 * way if we're starting with a file we've seen before, we'll put the
976 * line in the middle, otherwise, it won't work and we'll end up with
977 * the line at the top.
978 */
979 F_CLR(sp, SC_SCR_TOP)(((sp)->flags) &= ~((0x00000100)));
980 F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER)(((sp)->flags) |= ((0x00000020 | 0x00000080)));
981
982 /* Invalidate the cursor. */
983 F_SET(vip, VIP_CUR_INVALID)(((vip)->flags) |= ((0x0001)));
984
985 /* Paint the screen image from scratch. */
986 F_SET(vip, VIP_N_EX_PAINT)(((vip)->flags) |= ((0x0004)));
987
988 return (0);
989}
990
991/*
992 * v_dtoh --
993 * Move all but the current screen to the hidden queue.
994 */
995static void
996v_dtoh(SCR *sp)
997{
998 GS *gp;
999 SCR *tsp;
1000 int hidden;
1001
1002 /* Move all screens to the hidden queue, tossing screen maps. */
1003 hidden = 0;
1004 gp = sp->gp;
1005 while ((tsp = TAILQ_FIRST(&gp->dq)((&gp->dq)->tqh_first))) {
1006 free(_HMAP(tsp)(((VI_PRIVATE *)((tsp)->vi_private))->h_smap));
1007 _HMAP(tsp)(((VI_PRIVATE *)((tsp)->vi_private))->h_smap) = NULL((void *)0);
1008 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)
;
1009 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)
;
1010 ++hidden;
1011 }
1012
1013 /* Move current screen back to the display queue. */
1014 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)
;
1015 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)
;
1016
1017 /*
1018 * XXX
1019 * Don't bother internationalizing this message, it's going to
1020 * go away as soon as we have one-line screens. --TK
1021 */
1022 if (hidden > 1)
1023 msgq(sp, M_INFO,
1024 "%d screens backgrounded; use :display to list them",
1025 hidden - 1);
1026}
1027
1028/*
1029 * v_keyword --
1030 * Get the word (or non-word) the cursor is on.
1031 */
1032static int
1033v_keyword(SCR *sp)
1034{
1035 VI_PRIVATE *vip;
1036 size_t beg, end, len;
1037 int moved, state;
1038 char *p;
1039
1040 if (db_get(sp, sp->lno, DBG_FATAL0x001, &p, &len))
1041 return (1);
1042
1043 /*
1044 * !!!
1045 * Historically, tag commands skipped over any leading whitespace
1046 * characters. Make this true in general when using cursor words.
1047 * If movement, getting a cursor word implies moving the cursor to
1048 * its beginning. Refresh now.
1049 *
1050 * !!!
1051 * Find the beginning/end of the keyword. Keywords are currently
1052 * used for cursor-word searching and for tags. Historical vi
1053 * only used the word in a tag search from the cursor to the end
1054 * of the word, i.e. if the cursor was on the 'b' in " abc ", the
1055 * tag was "bc". For consistency, we make cursor word searches
1056 * follow the same rule.
1057 */
1058 for (moved = 0,
1059 beg = sp->cno; beg < len && isspace(p[beg]); moved = 1, ++beg);
1060 if (beg >= len) {
1061 msgq(sp, M_BERR, "Cursor not in a word");
1062 return (1);
1063 }
1064 if (moved) {
1065 sp->cno = beg;
1066 (void)vs_refresh(sp, 0);
1067 }
1068
1069 /* Find the end of the word. */
1070 for (state = inword(p[beg])(isalnum(p[beg]) || (p[beg]) == '_'),
1071 end = beg; ++end < len && state == inword(p[end])(isalnum(p[end]) || (p[end]) == '_'););
1072
1073 vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private));
1074 len = (end - beg);
1075 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; } }
;
1076 memmove(vip->keyw, p + beg, len);
1077 vip->keyw[len] = '\0'; /* XXX */
1078 return (0);
1079}
1080
1081/*
1082 * v_alias --
1083 * Check for a command alias.
1084 */
1085static VIKEYS const *
1086v_alias(SCR *sp, VICMD *vp, VIKEYS const *kp)
1087{
1088 CHAR_T push;
1089
1090 switch (vp->key) {
1091 case 'C': /* C -> c$ */
1092 push = '$';
1093 vp->key = 'c';
1094 break;
1095 case 'D': /* D -> d$ */
1096 push = '$';
1097 vp->key = 'd';
1098 break;
1099 case 'S': /* S -> c_ */
1100 push = '_';
1101 vp->key = 'c';
1102 break;
1103 case 'Y': /* Y -> y_ */
1104 push = '_';
1105 vp->key = 'y';
1106 break;
1107 default:
1108 return (kp);
1109 }
1110 return (v_event_push(sp,
1111 NULL((void *)0), &push, 1, CH_NOMAP0x04 | CH_QUOTED0x08) ? NULL((void *)0) : &vikeys[vp->key]);
1112}
1113
1114/*
1115 * v_count --
1116 * Return the next count.
1117 */
1118static int
1119v_count(SCR *sp, CHAR_T fkey, u_long *countp)
1120{
1121 EVENT ev;
1122 u_long count, tc;
1123
1124 ev.e_c_u_event._e_ch.c = fkey;
1125 count = tc = 0;
Although the value stored to 'tc' is used in the enclosing expression, the value is never actually read from 'tc'
1126 do {
1127 /*
1128 * XXX
1129 * Assume that overflow results in a smaller number.
1130 */
1131 tc = count * 10 + ev.e_c_u_event._e_ch.c - '0';
1132 if (count > tc) {
1133 /* Toss to the next non-digit. */
1134 do {
1135 if (v_key(sp, 0, &ev,
1136 EC_MAPCOMMAND0x002 | EC_MAPNODIGIT0x008) != GC_OK)
1137 return (1);
1138 } while (isdigit(ev.e_c_u_event._e_ch.c));
1139 msgq(sp, M_ERR,
1140 "Number larger than %lu", ULONG_MAX(9223372036854775807L *2UL+1UL));
1141 return (1);
1142 }
1143 count = tc;
1144 if (v_key(sp, 0, &ev, EC_MAPCOMMAND0x002 | EC_MAPNODIGIT0x008) != GC_OK)
1145 return (1);
1146 } while (isdigit(ev.e_c_u_event._e_ch.c));
1147 *countp = count;
1148 return (0);
1149}
1150
1151/*
1152 * v_key --
1153 * Return the next event.
1154 */
1155static gcret_t
1156v_key(SCR *sp, int command_events, EVENT *evp, u_int32_t ec_flags)
1157{
1158 u_int32_t quote;
1159
1160 for (quote = 0;;) {
1161 if (v_event_get(sp, evp, 0, ec_flags | quote))
1162 return (GC_FATAL);
1163 quote = 0;
1164
1165 switch (evp->e_event) {
1166 case E_CHARACTER:
1167 /*
1168 * !!!
1169 * Historically, ^V was ignored in the command stream,
1170 * although it had a useful side-effect of interrupting
1171 * mappings. Adding a quoting bit to the call probably
1172 * extends historic practice, but it feels right.
1173 */
1174 if (evp->e_value_u_event._e_ch.value == K_VLNEXT) {
1175 quote = EC_QUOTED0x010;
1176 break;
1177 }
1178 return (GC_OK);
1179 case E_ERR:
1180 case E_EOF:
1181 return (GC_FATAL);
1182 case E_INTERRUPT:
1183 /*
1184 * !!!
1185 * Historically, vi beeped on command level interrupts.
1186 *
1187 * Historically, vi exited to ex mode if no file was
1188 * named on the command line, and two interrupts were
1189 * generated in a row. (Just figured you might want
1190 * to know that.)
1191 */
1192 (void)sp->gp->scr_bell(sp);
1193 return (GC_INTERRUPT);
1194 case E_REPAINT:
1195 if (vs_repaint(sp, evp))
1196 return (GC_FATAL);
1197 break;
1198 case E_WRESIZE:
1199 return (GC_ERR);
1200 case E_QUIT:
1201 case E_WRITE:
1202 if (command_events)
1203 return (GC_EVENT);
1204 /* FALLTHROUGH */
1205 default:
1206 v_event_err(sp, evp);
1207 return (GC_ERR);
1208 }
1209 }
1210 /* NOTREACHED */
1211}
1212
1213#if defined(DEBUG) && defined(COMLOG)
1214/*
1215 * v_comlog --
1216 * Log the contents of the command structure.
1217 */
1218static void
1219v_comlog(SCR *sp, VICMD *vp)
1220{
1221 TRACE(sp, "vcmd: %c", vp->key);
1222 if (F_ISSET(vp, VC_BUFFER)(((vp)->flags) & ((0x00000200))))
1223 TRACE(sp, " buffer: %c", vp->buffer);
1224 if (F_ISSET(vp, VC_C1SET)(((vp)->flags) & ((0x00000800))))
1225 TRACE(sp, " c1: %lu", vp->count);
1226 if (F_ISSET(vp, VC_C2SET)(((vp)->flags) & ((0x00001000))))
1227 TRACE(sp, " c2: %lu", vp->count2);
1228 TRACE(sp, " flags: 0x%x\n", vp->flags);
1229}
1230#endif