Bug Summary

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'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name vi.c -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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/llvm16/lib/clang/16 -I /usr/src/usr.bin/vi/build -I /usr/src/usr.bin/vi/build/../include -I . -internal-isystem /usr/local/llvm16/lib/clang/16/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 -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/vi/build/../vi/vi.c
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
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 /* 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)
415ret: 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 */
438VIKEYS 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 */
457static gcret_t
458v_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) {
659usage: 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
700esc: 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 */
718static int
719v_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, &notused, 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 */
928static int
929v_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 */
999static void
1000v_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 */
1036static int
1037v_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 */
1089static VIKEYS const *
1090v_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 */
1122static int
1123v_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 */
1159static gcret_t
1160v_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 */
1222static void
1223v_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