Bug Summary

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

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))
1
Calling 'v_init'
15
Returning from 'v_init'
16
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;;) {
17
Loop condition is true. Entering loop body
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))
18
Assuming field 'i_cnt' is equal to 0
19
Assuming the condition is false
20
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))))
21
Assuming the condition is false
22
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))
23
Assuming the condition is false
24
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
)))
) {
25
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))))
)
26
Assuming field 'i_cnt' is equal to 0
119 mapped = 1;
120 else {
121 if (log_cursor(sp))
27
Assuming the condition is false
28
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)) {
29
Assuming field 'clen' is not equal to 0
30
Taking true branch
132 vp->kp = &vikeys[':'];
133 goto ex_continue;
31
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))
32
Assuming the condition is false
33
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)))) {
34
Assuming the condition is false
35
Taking false branch
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) {
36
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)))) {
37
Control jumps to 'case 32:' at line 318
317 case 0:
318 case VM_RCM_SET0x00000020:
319 break;
38
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))) ||
39
Assuming the condition is false
347 (F_ISSET(vp, V_ABS_L)(((vp)->flags) & ((0x00010000))) && sp->lno != abs.lno) ||
40
Assuming the condition is false
348 (F_ISSET(vp, V_ABS_C)(((vp)->flags) & ((0x00008000))) &&
41
Assuming the condition is true
349 (sp->lno != abs.lno || sp->cno != abs.cno))) &&
42
The right operand of '!=' is a garbage value
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))
2
Assuming the condition is false
3
Taking false branch
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)
;
4
Assuming the condition is false
5
'?' condition is false
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)
;
6
Assuming the condition is false
7
'?' condition is false
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)
;
8
Assuming the condition is false
9
'?' condition is false
954 if (sp->rows != 1) {
10
Assuming field 'rows' is equal to 1
11
Taking false branch
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); } }
;
12
Assuming the condition is false
13
Taking false branch
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);
14
Returning zero, which participates in a condition later
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;
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