GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../vi/v_ex.c Lines: 0 196 0.0 %
Date: 2017-11-07 Branches: 0 101 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: v_ex.c,v 1.13 2016/01/06 22:28:52 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 <limits.h>
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <string.h>
23
#include <unistd.h>
24
25
#include "../common/common.h"
26
#include "vi.h"
27
28
static int v_ecl(SCR *);
29
static int v_ecl_init(SCR *);
30
static int v_ecl_log(SCR *, TEXT *);
31
static int v_ex_done(SCR *, VICMD *);
32
static int v_exec_ex(SCR *, VICMD *, EXCMD *);
33
34
/*
35
 * v_again -- &
36
 *	Repeat the previous substitution.
37
 *
38
 * PUBLIC: int v_again(SCR *, VICMD *);
39
 */
40
int
41
v_again(SCR *sp, VICMD *vp)
42
{
43
	ARGS *ap[2], a;
44
	EXCMD cmd;
45
46
	ex_cinit(&cmd, C_SUBAGAIN, 2, vp->m_start.lno, vp->m_start.lno, 1, ap);
47
	ex_cadd(&cmd, &a, "", 1);
48
49
	return (v_exec_ex(sp, vp, &cmd));
50
}
51
52
/*
53
 * v_exmode -- Q
54
 *	Switch the editor into EX mode.
55
 *
56
 * PUBLIC: int v_exmode(SCR *, VICMD *);
57
 */
58
int
59
v_exmode(SCR *sp, VICMD *vp)
60
{
61
	GS *gp;
62
63
	gp = sp->gp;
64
65
	/* Try and switch screens -- the screen may not permit it. */
66
	if (gp->scr_screen(sp, SC_EX)) {
67
		msgq(sp, M_ERR,
68
		    "The Q command requires the ex terminal interface");
69
		return (1);
70
	}
71
	(void)gp->scr_attr(sp, SA_ALTERNATE, 0);
72
73
	/* Save the current cursor position. */
74
	sp->frp->lno = sp->lno;
75
	sp->frp->cno = sp->cno;
76
	F_SET(sp->frp, FR_CURSORSET);
77
78
	/* Switch to ex mode. */
79
	F_CLR(sp, SC_VI | SC_SCR_VI);
80
	F_SET(sp, SC_EX);
81
82
	/* Move out of the vi screen. */
83
	(void)ex_puts(sp, "\n");
84
85
	return (0);
86
}
87
88
/*
89
 * v_join -- [count]J
90
 *	Join lines together.
91
 *
92
 * PUBLIC: int v_join(SCR *, VICMD *);
93
 */
94
int
95
v_join(SCR *sp, VICMD *vp)
96
{
97
	EXCMD cmd;
98
	int lno;
99
100
	/*
101
	 * YASC.
102
	 * The general rule is that '#J' joins # lines, counting the current
103
	 * line.  However, 'J' and '1J' are the same as '2J', i.e. join the
104
	 * current and next lines.  This doesn't map well into the ex command
105
	 * (which takes two line numbers), so we handle it here.  Note that
106
	 * we never test for EOF -- historically going past the end of file
107
	 * worked just fine.
108
	 */
109
	lno = vp->m_start.lno + 1;
110
	if (F_ISSET(vp, VC_C1SET) && vp->count > 2)
111
		lno = vp->m_start.lno + (vp->count - 1);
112
113
	ex_cinit(&cmd, C_JOIN, 2, vp->m_start.lno, lno, 0, NULL);
114
	return (v_exec_ex(sp, vp, &cmd));
115
}
116
117
/*
118
 * v_shiftl -- [count]<motion
119
 *	Shift lines left.
120
 *
121
 * PUBLIC: int v_shiftl(SCR *, VICMD *);
122
 */
123
int
124
v_shiftl(SCR *sp, VICMD *vp)
125
{
126
	ARGS *ap[2], a;
127
	EXCMD cmd;
128
129
	ex_cinit(&cmd, C_SHIFTL, 2, vp->m_start.lno, vp->m_stop.lno, 0, ap);
130
	ex_cadd(&cmd, &a, "<", 1);
131
	return (v_exec_ex(sp, vp, &cmd));
132
}
133
134
/*
135
 * v_shiftr -- [count]>motion
136
 *	Shift lines right.
137
 *
138
 * PUBLIC: int v_shiftr(SCR *, VICMD *);
139
 */
140
int
141
v_shiftr(SCR *sp, VICMD *vp)
142
{
143
	ARGS *ap[2], a;
144
	EXCMD cmd;
145
146
	ex_cinit(&cmd, C_SHIFTR, 2, vp->m_start.lno, vp->m_stop.lno, 0, ap);
147
	ex_cadd(&cmd, &a, ">", 1);
148
	return (v_exec_ex(sp, vp, &cmd));
149
}
150
151
/*
152
 * v_suspend -- ^Z
153
 *	Suspend vi.
154
 *
155
 * PUBLIC: int v_suspend(SCR *, VICMD *);
156
 */
157
int
158
v_suspend(SCR *sp, VICMD *vp)
159
{
160
	ARGS *ap[2], a;
161
	EXCMD cmd;
162
163
	ex_cinit(&cmd, C_STOP, 0, OOBLNO, OOBLNO, 0, ap);
164
	ex_cadd(&cmd, &a, "suspend", sizeof("suspend") - 1);
165
	return (v_exec_ex(sp, vp, &cmd));
166
}
167
168
/*
169
 * v_switch -- ^^
170
 *	Switch to the previous file.
171
 *
172
 * PUBLIC: int v_switch(SCR *, VICMD *);
173
 */
174
int
175
v_switch(SCR *sp, VICMD *vp)
176
{
177
	ARGS *ap[2], a;
178
	EXCMD cmd;
179
	char *name;
180
181
	/*
182
	 * Try the alternate file name, then the previous file
183
	 * name.  Use the real name, not the user's current name.
184
	 */
185
	if (sp->alt_name == NULL) {
186
		msgq(sp, M_ERR, "No previous file to edit");
187
		return (1);
188
	}
189
	if ((name = strdup(sp->alt_name)) == NULL) {
190
		msgq(sp, M_SYSERR, NULL);
191
		return (1);
192
	}
193
194
	/* If autowrite is set, write out the file. */
195
	if (file_m1(sp, 0, FS_ALL)) {
196
		free(name);
197
		return (1);
198
	}
199
200
	ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, ap);
201
	ex_cadd(&cmd, &a, name, strlen(name));
202
	return (v_exec_ex(sp, vp, &cmd));
203
}
204
205
/*
206
 * v_tagpush -- ^[
207
 *	Do a tag search on the cursor keyword.
208
 *
209
 * PUBLIC: int v_tagpush(SCR *, VICMD *);
210
 */
211
int
212
v_tagpush(SCR *sp, VICMD *vp)
213
{
214
	ARGS *ap[2], a;
215
	EXCMD cmd;
216
217
	ex_cinit(&cmd, C_TAG, 0, OOBLNO, 0, 0, ap);
218
	ex_cadd(&cmd, &a, VIP(sp)->keyw, strlen(VIP(sp)->keyw));
219
	return (v_exec_ex(sp, vp, &cmd));
220
}
221
222
/*
223
 * v_tagpop -- ^T
224
 *	Pop the tags stack.
225
 *
226
 * PUBLIC: int v_tagpop(SCR *, VICMD *);
227
 */
228
int
229
v_tagpop(SCR *sp, VICMD *vp)
230
{
231
	EXCMD cmd;
232
233
	ex_cinit(&cmd, C_TAGPOP, 0, OOBLNO, 0, 0, NULL);
234
	return (v_exec_ex(sp, vp, &cmd));
235
}
236
237
/*
238
 * v_filter -- [count]!motion command(s)
239
 *	Run range through shell commands, replacing text.
240
 *
241
 * PUBLIC: int v_filter(SCR *, VICMD *);
242
 */
243
int
244
v_filter(SCR *sp, VICMD *vp)
245
{
246
	EXCMD cmd;
247
	TEXT *tp;
248
249
	/*
250
	 * !!!
251
	 * Historical vi permitted "!!" in an empty file, and it's handled
252
	 * as a special case in the ex_bang routine.  Don't modify this setup
253
	 * without understanding that one.  In particular, note that we're
254
	 * manipulating the ex argument structures behind ex's back.
255
	 *
256
	 * !!!
257
	 * Historical vi did not permit the '!' command to be associated with
258
	 * a non-line oriented motion command, in general, although it did
259
	 * with search commands.  So, !f; and !w would fail, but !/;<CR>
260
	 * would succeed, even if they all moved to the same location in the
261
	 * current line.  I don't see any reason to disallow '!' using any of
262
	 * the possible motion commands.
263
	 *
264
	 * !!!
265
	 * Historical vi ran the last bang command if N or n was used as the
266
	 * search motion.
267
	 */
268
	if (F_ISSET(vp, VC_ISDOT) ||
269
	    ISCMD(vp->rkp, 'N') || ISCMD(vp->rkp, 'n')) {
270
		ex_cinit(&cmd, C_BANG,
271
		    2, vp->m_start.lno, vp->m_stop.lno, 0, NULL);
272
		EXP(sp)->argsoff = 0;			/* XXX */
273
274
		if (argv_exp1(sp, &cmd, "!", 1, 1))
275
			return (1);
276
		cmd.argc = EXP(sp)->argsoff;		/* XXX */
277
		cmd.argv = EXP(sp)->args;		/* XXX */
278
		return (v_exec_ex(sp, vp, &cmd));
279
	}
280
281
	/* Get the command from the user. */
282
	if (v_tcmd(sp, vp,
283
	    '!', TXT_BS | TXT_CR | TXT_ESCAPE | TXT_FILEC | TXT_PROMPT))
284
		return (1);
285
286
	/*
287
	 * Check to see if the user changed their mind.
288
	 *
289
	 * !!!
290
	 * Entering <escape> on an empty line was historically an error,
291
	 * this implementation doesn't bother.
292
	 */
293
	tp = TAILQ_FIRST(&sp->tiq);
294
	if (tp->term != TERM_OK) {
295
		vp->m_final.lno = sp->lno;
296
		vp->m_final.cno = sp->cno;
297
		return (0);
298
	}
299
300
	/* Home the cursor. */
301
	vs_home(sp);
302
303
	ex_cinit(&cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0, NULL);
304
	EXP(sp)->argsoff = 0;			/* XXX */
305
306
	if (argv_exp1(sp, &cmd, tp->lb + 1, tp->len - 1, 1))
307
		return (1);
308
	cmd.argc = EXP(sp)->argsoff;		/* XXX */
309
	cmd.argv = EXP(sp)->args;		/* XXX */
310
	return (v_exec_ex(sp, vp, &cmd));
311
}
312
313
/*
314
 * v_event_exec --
315
 *	Execute some command(s) based on an event.
316
 *
317
 * PUBLIC: int v_event_exec(SCR *, VICMD *);
318
 */
319
int
320
v_event_exec(SCR *sp, VICMD *vp)
321
{
322
	EXCMD cmd;
323
324
	switch (vp->ev.e_event) {
325
	case E_QUIT:
326
		ex_cinit(&cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0, NULL);
327
		break;
328
	case E_WRITE:
329
		ex_cinit(&cmd, C_WRITE, 0, OOBLNO, OOBLNO, 0, NULL);
330
		break;
331
	default:
332
		abort();
333
	}
334
	return (v_exec_ex(sp, vp, &cmd));
335
}
336
337
/*
338
 * v_exec_ex --
339
 *	Execute an ex command.
340
 */
341
static int
342
v_exec_ex(SCR *sp, VICMD *vp, EXCMD *exp)
343
{
344
	int rval;
345
346
	rval = exp->cmd->fn(sp, exp);
347
	return (v_ex_done(sp, vp) || rval);
348
}
349
350
/*
351
 * v_ex -- :
352
 *	Execute a colon command line.
353
 *
354
 * PUBLIC: int v_ex(SCR *, VICMD *);
355
 */
356
int
357
v_ex(SCR *sp, VICMD *vp)
358
{
359
	GS *gp;
360
	TEXT *tp;
361
	int do_cedit, do_resolution, ifcontinue;
362
363
	gp = sp->gp;
364
365
	/*
366
	 * !!!
367
	 * If we put out more than a single line of messages, or ex trashes
368
	 * the screen, the user may continue entering ex commands.  We find
369
	 * this out when we do the screen/message resolution.  We can't enter
370
	 * completely into ex mode however, because the user can elect to
371
	 * return into vi mode by entering any key, i.e. we have to be in raw
372
	 * mode.
373
	 */
374
	for (do_cedit = do_resolution = 0;;) {
375
		/*
376
		 * !!!
377
		 * There may already be an ex command waiting to run.  If
378
		 * so, we continue with it.
379
		 */
380
		if (!EXCMD_RUNNING(gp)) {
381
			/* Get a command. */
382
			if (v_tcmd(sp, vp, ':',
383
			    TXT_BS | TXT_CEDIT | TXT_FILEC | TXT_PROMPT))
384
				return (1);
385
			tp = TAILQ_FIRST(&sp->tiq);
386
387
			/*
388
			 * If the user entered a single <esc>, they want to
389
			 * edit their colon command history.  If they already
390
			 * entered some text, move it into the edit history.
391
			 */
392
			if (tp->term == TERM_CEDIT) {
393
				if (tp->len > 1 && v_ecl_log(sp, tp))
394
					return (1);
395
				do_cedit = 1;
396
				break;
397
			}
398
399
			/* If the user changed their mind, return. */
400
			if (tp->term != TERM_OK)
401
				break;
402
403
			/* Log the command. */
404
			if (O_STR(sp, O_CEDIT) != NULL && v_ecl_log(sp, tp))
405
				return (1);
406
407
			/* Push a command on the command stack. */
408
			if (ex_run_str(sp, NULL, tp->lb, tp->len, 0, 1))
409
				return (1);
410
		}
411
412
		/* Home the cursor. */
413
		vs_home(sp);
414
415
		/*
416
		 * !!!
417
		 * If the editor wrote the screen behind curses back, put out
418
		 * a <newline> so that we don't overwrite the user's command
419
		 * with its output or the next want-to-continue? message.  This
420
		 * doesn't belong here, but I can't find another place to put
421
		 * it.  See, we resolved the output from the last ex command,
422
		 * and the user entered another one.  This is the only place
423
		 * where we have control before the ex command writes output.
424
		 * We could get control in vs_msg(), but we have no way to know
425
		 * if command didn't put out any output when we try and resolve
426
		 * this command.  This fixes a bug where combinations of ex
427
		 * commands, e.g. ":set<CR>:!date<CR>:set" didn't look right.
428
		 */
429
		if (F_ISSET(sp, SC_SCR_EXWROTE))
430
			(void)putchar('\n');
431
432
		/* Call the ex parser. */
433
		(void)ex_cmd(sp);
434
435
		/* Flush ex messages. */
436
		(void)ex_fflush(sp);
437
438
		/* Resolve any messages. */
439
		if (vs_ex_resolve(sp, &ifcontinue))
440
			return (1);
441
442
		/*
443
		 * Continue or return.  If continuing, make sure that we
444
		 * eventually do resolution.
445
		 */
446
		if (!ifcontinue)
447
			break;
448
		do_resolution = 1;
449
450
		/* If we're continuing, it's a new command. */
451
		++sp->ccnt;
452
	}
453
454
	/*
455
	 * If the user previously continued an ex command, we have to do
456
	 * resolution to clean up the screen.  Don't wait, we already did
457
	 * that.
458
	 */
459
	if (do_resolution) {
460
		F_SET(sp, SC_EX_WAIT_NO);
461
		if (vs_ex_resolve(sp, &ifcontinue))
462
			return (1);
463
	}
464
465
	/* Cleanup from the ex command. */
466
	if (v_ex_done(sp, vp))
467
		return (1);
468
469
	/* The user may want to edit their colon command history. */
470
	if (do_cedit)
471
		return (v_ecl(sp));
472
473
	return (0);
474
}
475
476
/*
477
 * v_ex_done --
478
 *	Cleanup from an ex command.
479
 */
480
static int
481
v_ex_done(SCR *sp, VICMD *vp)
482
{
483
	size_t len;
484
485
	/*
486
	 * The only cursor modifications are real, however, the underlying
487
	 * line may have changed; don't trust anything.  This code has been
488
	 * a remarkably fertile place for bugs.  Do a reality check on a
489
	 * cursor value, and make sure it's okay.  If necessary, change it.
490
	 * Ex keeps track of the line number, but it cares less about the
491
	 * column and it may have disappeared.
492
	 *
493
	 * Don't trust ANYTHING.
494
	 *
495
	 * XXX
496
	 * Ex will soon have to start handling the column correctly; see
497
	 * the POSIX 1003.2 standard.
498
	 */
499
	if (db_eget(sp, sp->lno, NULL, &len, NULL)) {
500
		sp->lno = 1;
501
		sp->cno = 0;
502
	} else if (sp->cno >= len)
503
		sp->cno = len ? len - 1 : 0;
504
505
	vp->m_final.lno = sp->lno;
506
	vp->m_final.cno = sp->cno;
507
508
	/*
509
	 * Don't re-adjust the cursor after executing an ex command,
510
	 * and ex movements are permanent.
511
	 */
512
	F_CLR(vp, VM_RCM_MASK);
513
	F_SET(vp, VM_RCM_SET);
514
515
	return (0);
516
}
517
518
/*
519
 * v_ecl --
520
 *	Start an edit window on the colon command-line commands.
521
 */
522
static int
523
v_ecl(SCR *sp)
524
{
525
	GS *gp;
526
	SCR *new;
527
528
	/* Initialize the screen, if necessary. */
529
	gp = sp->gp;
530
	if (gp->ccl_sp == NULL && v_ecl_init(sp))
531
		return (1);
532
533
	/* Get a new screen. */
534
	if (screen_init(gp, sp, &new))
535
		return (1);
536
	if (vs_split(sp, new, 1)) {
537
		(void)screen_end(new);
538
		return (1);
539
	}
540
541
	/* Attach to the screen. */
542
	new->ep = gp->ccl_sp->ep;
543
	++new->ep->refcnt;
544
545
	new->frp = gp->ccl_sp->frp;
546
	new->frp->flags = sp->frp->flags;
547
548
	/* Move the cursor to the end. */
549
	(void)db_last(new, &new->lno);
550
	if (new->lno == 0)
551
		new->lno = 1;
552
553
	/* Remember the originating window. */
554
	sp->ccl_parent = sp;
555
556
	/* It's a special window. */
557
	F_SET(new, SC_COMEDIT);
558
559
	/* Set up the switch. */
560
	sp->nextdisp = new;
561
	F_SET(sp, SC_SSWITCH);
562
	return (0);
563
}
564
565
/*
566
 * v_ecl_exec --
567
 *	Execute a command from a colon command-line window.
568
 *
569
 * PUBLIC: int v_ecl_exec(SCR *);
570
 */
571
int
572
v_ecl_exec(SCR *sp)
573
{
574
	size_t len;
575
	char *p;
576
577
	if (db_get(sp, sp->lno, 0, &p, &len) && sp->lno == 1) {
578
		v_emsg(sp, NULL, VIM_EMPTY);
579
		return (1);
580
	}
581
	if (len == 0) {
582
		msgq(sp, M_BERR, "No ex command to execute");
583
		return (1);
584
	}
585
586
	/* Push the command on the command stack. */
587
	if (ex_run_str(sp, NULL, p, len, 0, 0))
588
		return (1);
589
590
	/* Set up the switch. */
591
	sp->nextdisp = sp->ccl_parent;
592
	F_SET(sp, SC_EXIT);
593
	return (0);
594
}
595
596
/*
597
 * v_ecl_log --
598
 *	Log a command into the colon command-line log file.
599
 */
600
static int
601
v_ecl_log(SCR *sp, TEXT *tp)
602
{
603
	EXF *save_ep;
604
	recno_t lno;
605
	int rval;
606
607
	/* Initialize the screen, if necessary. */
608
	if (sp->gp->ccl_sp == NULL && v_ecl_init(sp))
609
		return (1);
610
611
	/*
612
	 * Don't log colon command window commands into the colon command
613
	 * window...
614
	 */
615
	if (sp->ep == sp->gp->ccl_sp->ep)
616
		return (0);
617
618
	/*
619
	 * XXX
620
	 * Swap the current EXF with the colon command file EXF.  This
621
	 * isn't pretty, but too many routines "know" that sp->ep points
622
	 * to the current EXF.
623
	 */
624
	save_ep = sp->ep;
625
	sp->ep = sp->gp->ccl_sp->ep;
626
	if (db_last(sp, &lno)) {
627
		sp->ep = save_ep;
628
		return (1);
629
	}
630
	rval = db_append(sp, 0, lno, tp->lb, tp->len);
631
	sp->ep = save_ep;
632
	return (rval);
633
}
634
635
/*
636
 * v_ecl_init --
637
 *	Initialize the colon command-line log file.
638
 */
639
static int
640
v_ecl_init(SCR *sp)
641
{
642
	FREF *frp;
643
	GS *gp;
644
645
	gp = sp->gp;
646
647
	/* Get a temporary file. */
648
	if ((frp = file_add(sp, NULL)) == NULL)
649
		return (1);
650
651
	/*
652
	 * XXX
653
	 * Create a screen -- the file initialization code wants one.
654
	 */
655
	if (screen_init(gp, sp, &gp->ccl_sp))
656
		return (1);
657
	if (file_init(gp->ccl_sp, frp, NULL, 0)) {
658
		(void)screen_end(gp->ccl_sp);
659
		return (1);
660
	}
661
662
	/* The underlying file isn't recoverable. */
663
	F_CLR(gp->ccl_sp->ep, F_RCV_ON);
664
665
	return (0);
666
}