Bug Summary

File:src/usr.bin/vi/build/../vi/vi.c
Warning:line 347, column 40
The right operand of '!=' is a garbage value

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))
1
Taking false branch
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))
2
Loop condition is true. Entering loop body
3
Assuming field 'i_cnt' is equal to 0
4
Assuming the condition is false
5
Taking false branch
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))))
6
Assuming the condition is false
7
Taking false branch
100 F_CLR(vip, VIP_S_REFRESH)(((vip)->flags) &= ~((0x0100)));
101 else {
102 sp->showmode = SM_COMMAND;
103 if (vs_refresh(sp, 0))
8
Assuming the condition is false
9
Taking false branch
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
)))
) {
10
Taking true branch
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))))
)
11
Assuming field 'i_cnt' is equal to 0
119 mapped = 1;
120 else {
121 if (log_cursor(sp))
12
Assuming the condition is false
13
Taking false branch
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)) {
14
Assuming field 'clen' is not equal to 0
15
Taking true branch
132 vp->kp = &vikeys[':'];
133 goto ex_continue;
16
Control jumps to line 232
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))
17
Assuming the condition is false
18
Taking false branch
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)))) {
19
Assuming the condition is false
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) {
20
Taking false branch
21
Assuming the condition is false
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)))) {
22
Control jumps to 'case 32:' at line 318
317 case 0:
318 case VM_RCM_SET0x00000020:
319 break;
23
Execution continues on line 339
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))) ||
24
Assuming the condition is false
347 (F_ISSET(vp, V_ABS_L)(((vp)->flags) & ((0x00010000))) && sp->lno != abs.lno) ||
25
Assuming the condition is true
26
The right operand of '!=' is a garbage value
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;
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