GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../cl/cl_funcs.c Lines: 0 164 0.0 %
Date: 2017-11-07 Branches: 0 145 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: cl_funcs.c,v 1.20 2016/05/27 09:18:11 martijn Exp $	*/
2
3
/*-
4
 * Copyright (c) 1993, 1994
5
 *	The Regents of the University of California.  All rights reserved.
6
 * Copyright (c) 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 <curses.h>
21
#include <signal.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <term.h>
26
#include <termios.h>
27
#include <unistd.h>
28
29
#include "../common/common.h"
30
#include "../vi/vi.h"
31
#include "cl.h"
32
33
/*
34
 * cl_addstr --
35
 *	Add len bytes from the string at the cursor, advancing the cursor.
36
 *
37
 * PUBLIC: int cl_addstr(SCR *, const char *, size_t);
38
 */
39
int
40
cl_addstr(SCR *sp, const char *str, size_t len)
41
{
42
	size_t oldy, oldx;
43
	int iv;
44
45
	/*
46
	 * If ex isn't in control, it's the last line of the screen and
47
	 * it's a split screen, use inverse video.
48
	 */
49
	iv = 0;
50
	getyx(stdscr, oldy, oldx);
51
	if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
52
	    oldy == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
53
		iv = 1;
54
		(void)standout();
55
	}
56
57
	if (addnstr(str, len) == ERR)
58
		return (1);
59
60
	if (iv)
61
		(void)standend();
62
	return (0);
63
}
64
65
/*
66
 * cl_attr --
67
 *	Toggle a screen attribute on/off.
68
 *
69
 * PUBLIC: int cl_attr(SCR *, scr_attr_t, int);
70
 */
71
int
72
cl_attr(SCR *sp, scr_attr_t attribute, int on)
73
{
74
	CL_PRIVATE *clp;
75
76
	clp = CLP(sp);
77
78
	switch (attribute) {
79
	case SA_ALTERNATE:
80
	/*
81
	 * !!!
82
	 * There's a major layering violation here.  The problem is that the
83
	 * X11 xterm screen has what's known as an "alternate" screen.  Some
84
	 * xterm termcap/terminfo entries include sequences to switch to/from
85
	 * that alternate screen as part of the ti/te (smcup/rmcup) strings.
86
	 * Vi runs in the alternate screen, so that you are returned to the
87
	 * same screen contents on exit from vi that you had when you entered
88
	 * vi.  Further, when you run :shell, or :!date or similar ex commands,
89
	 * you also see the original screen contents.  This wasn't deliberate
90
	 * on vi's part, it's just that it historically sent terminal init/end
91
	 * sequences at those times, and the addition of the alternate screen
92
	 * sequences to the strings changed the behavior of vi.  The problem
93
	 * caused by this is that we don't want to switch back to the alternate
94
	 * screen while getting a new command from the user, when the user is
95
	 * continuing to enter ex commands, e.g.:
96
	 *
97
	 *	:!date				<<< switch to original screen
98
	 *	[Hit return to continue]	<<< prompt user to continue
99
	 *	:command			<<< get command from user
100
	 *
101
	 * Note that the :command input is a true vi input mode, e.g., input
102
	 * maps and abbreviations are being done.  So, we need to be able to
103
	 * switch back into the vi screen mode, without flashing the screen.
104
	 *
105
	 * To make matters worse, the curses initscr() and endwin() calls will
106
	 * do this automatically -- so, this attribute isn't as controlled by
107
	 * the higher level screen as closely as one might like.
108
	 */
109
	if (on) {
110
		if (clp->ti_te != TI_SENT) {
111
			clp->ti_te = TI_SENT;
112
			if (clp->smcup == NULL)
113
				(void)cl_getcap(sp, "smcup", &clp->smcup);
114
			if (clp->smcup != NULL)
115
				(void)tputs(clp->smcup, 1, cl_putchar);
116
		}
117
	} else
118
		if (clp->ti_te != TE_SENT) {
119
			clp->ti_te = TE_SENT;
120
			if (clp->rmcup == NULL)
121
				(void)cl_getcap(sp, "rmcup", &clp->rmcup);
122
			if (clp->rmcup != NULL)
123
				(void)tputs(clp->rmcup, 1, cl_putchar);
124
			(void)fflush(stdout);
125
		}
126
		(void)fflush(stdout);
127
		break;
128
	case SA_INVERSE:
129
		if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
130
			if (clp->smso == NULL)
131
				return (1);
132
			if (on)
133
				(void)tputs(clp->smso, 1, cl_putchar);
134
			else
135
				(void)tputs(clp->rmso, 1, cl_putchar);
136
			(void)fflush(stdout);
137
		} else {
138
			if (on)
139
				(void)standout();
140
			else
141
				(void)standend();
142
		}
143
		break;
144
	default:
145
		abort();
146
	}
147
	return (0);
148
}
149
150
/*
151
 * cl_baud --
152
 *	Return the baud rate.
153
 *
154
 * PUBLIC: int cl_baud(SCR *, u_long *);
155
 */
156
int
157
cl_baud(SCR *sp, u_long *ratep)
158
{
159
	CL_PRIVATE *clp;
160
161
	/*
162
	 * XXX
163
	 * There's no portable way to get a "baud rate" -- cfgetospeed(3)
164
	 * returns the value associated with some #define, which we may
165
	 * never have heard of, or which may be a purely local speed.  Vi
166
	 * only cares if it's SLOW (w300), slow (w1200) or fast (w9600).
167
	 * Try and detect the slow ones, and default to fast.
168
	 */
169
	clp = CLP(sp);
170
	switch (cfgetospeed(&clp->orig)) {
171
	case B50:
172
	case B75:
173
	case B110:
174
	case B134:
175
	case B150:
176
	case B200:
177
	case B300:
178
	case B600:
179
		*ratep = 600;
180
		break;
181
	case B1200:
182
		*ratep = 1200;
183
		break;
184
	default:
185
		*ratep = 9600;
186
		break;
187
	}
188
	return (0);
189
}
190
191
/*
192
 * cl_bell --
193
 *	Ring the bell/flash the screen.
194
 *
195
 * PUBLIC: int cl_bell(SCR *);
196
 */
197
int
198
cl_bell(SCR *sp)
199
{
200
	if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
201
		(void)write(STDOUT_FILENO, "\07", 1);		/* \a */
202
	else {
203
		/*
204
		 * If the screen has not been setup we cannot call
205
		 * curses routines yet.
206
		 */
207
		if (F_ISSET(sp, SC_SCR_VI)) {
208
			/*
209
			 * Vi has an edit option which determines if the
210
			 * terminal should be beeped or the screen flashed.
211
			 */
212
			if (O_ISSET(sp, O_FLASH))
213
				(void)flash();
214
			else
215
				(void)beep();
216
		} else if (!O_ISSET(sp, O_FLASH))
217
			(void)write(STDOUT_FILENO, "\07", 1);
218
	}
219
	return (0);
220
}
221
222
/*
223
 * cl_clrtoeol --
224
 *	Clear from the current cursor to the end of the line.
225
 *
226
 * PUBLIC: int cl_clrtoeol(SCR *);
227
 */
228
int
229
cl_clrtoeol(SCR *sp)
230
{
231
	return (clrtoeol() == ERR);
232
}
233
234
/*
235
 * cl_cursor --
236
 *	Return the current cursor position.
237
 *
238
 * PUBLIC: int cl_cursor(SCR *, size_t *, size_t *);
239
 */
240
int
241
cl_cursor(SCR *sp, size_t *yp, size_t *xp)
242
{
243
	/*
244
	 * The curses screen support splits a single underlying curses screen
245
	 * into multiple screens to support split screen semantics.  For this
246
	 * reason the returned value must be adjusted to be relative to the
247
	 * current screen, and not absolute.  Screens that implement the split
248
	 * using physically distinct screens won't need this hack.
249
	 */
250
	getyx(stdscr, *yp, *xp);
251
	*yp -= sp->woff;
252
	return (0);
253
}
254
255
/*
256
 * cl_deleteln --
257
 *	Delete the current line, scrolling all lines below it.
258
 *
259
 * PUBLIC: int cl_deleteln(SCR *);
260
 */
261
int
262
cl_deleteln(SCR *sp)
263
{
264
	size_t oldy, oldx;
265
266
	/*
267
	 * This clause is required because the curses screen uses reverse
268
	 * video to delimit split screens.  If the screen does not do this,
269
	 * this code won't be necessary.
270
	 *
271
	 * If the bottom line was in reverse video, rewrite it in normal
272
	 * video before it's scrolled.
273
	 *
274
	 * Check for the existence of a chgat function; XSI requires it, but
275
	 * historic implementations of System V curses don't.   If it's not
276
	 * a #define, we'll fall back to doing it by hand, which is slow but
277
	 * acceptable.
278
	 *
279
	 * By hand means walking through the line, retrieving and rewriting
280
	 * each character.  Curses has no EOL marker, so track strings of
281
	 * spaces, and copy the trailing spaces only if there's a non-space
282
	 * character following.
283
	 */
284
	if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) {
285
		getyx(stdscr, oldy, oldx);
286
		mvchgat(RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
287
		(void)move(oldy, oldx);
288
	}
289
290
	/*
291
	 * The bottom line is expected to be blank after this operation,
292
	 * and other screens must support that semantic.
293
	 */
294
	return (deleteln() == ERR);
295
}
296
297
/*
298
 * cl_ex_adjust --
299
 *	Adjust the screen for ex.  This routine is purely for standalone
300
 *	ex programs.  All special purpose, all special case.
301
 *
302
 * PUBLIC: int cl_ex_adjust(SCR *, exadj_t);
303
 */
304
int
305
cl_ex_adjust(SCR *sp, exadj_t action)
306
{
307
	CL_PRIVATE *clp;
308
	int cnt;
309
310
	clp = CLP(sp);
311
	switch (action) {
312
	case EX_TERM_SCROLL:
313
		/* Move the cursor up one line if that's possible. */
314
		if (clp->cuu1 != NULL)
315
			(void)tputs(clp->cuu1, 1, cl_putchar);
316
		else if (clp->cup != NULL)
317
			(void)tputs(tgoto(clp->cup,
318
			    0, LINES - 2), 1, cl_putchar);
319
		else
320
			return (0);
321
		/* FALLTHROUGH */
322
	case EX_TERM_CE:
323
		/* Clear the line. */
324
		if (clp->el != NULL) {
325
			(void)putchar('\r');
326
			(void)tputs(clp->el, 1, cl_putchar);
327
		} else {
328
			/*
329
			 * Historically, ex didn't erase the line, so, if the
330
			 * displayed line was only a single glyph, and <eof>
331
			 * was more than one glyph, the output would not fully
332
			 * overwrite the user's input.  To fix this, output
333
			 * the maxiumum character number of spaces.  Note,
334
			 * this won't help if the user entered extra prompt
335
			 * or <blank> characters before the command character.
336
			 * We'd have to do a lot of work to make that work, and
337
			 * it's almost certainly not worth the effort.
338
			 */
339
			for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
340
				(void)putchar('\b');
341
			for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
342
				(void)putchar(' ');
343
			(void)putchar('\r');
344
			(void)fflush(stdout);
345
		}
346
		break;
347
	default:
348
		abort();
349
	}
350
	return (0);
351
}
352
353
/*
354
 * cl_insertln --
355
 *	Push down the current line, discarding the bottom line.
356
 *
357
 * PUBLIC: int cl_insertln(SCR *);
358
 */
359
int
360
cl_insertln(SCR *sp)
361
{
362
	/*
363
	 * The current line is expected to be blank after this operation,
364
	 * and the screen must support that semantic.
365
	 */
366
	return (insertln() == ERR);
367
}
368
369
/*
370
 * cl_keyval --
371
 *	Return the value for a special key.
372
 *
373
 * PUBLIC: int cl_keyval(SCR *, scr_keyval_t, CHAR_T *, int *);
374
 */
375
int
376
cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep)
377
{
378
	CL_PRIVATE *clp;
379
380
	/*
381
	 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990,
382
	 * VWERASE is a 4BSD extension.
383
	 */
384
	clp = CLP(sp);
385
	switch (val) {
386
	case KEY_VEOF:
387
		*dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE;
388
		break;
389
	case KEY_VERASE:
390
		*dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE;
391
		break;
392
	case KEY_VKILL:
393
		*dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE;
394
		break;
395
	case KEY_VWERASE:
396
		*dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE;
397
		break;
398
	default:
399
		*dnep = 1;
400
		break;
401
	}
402
	return (0);
403
}
404
405
/*
406
 * cl_move --
407
 *	Move the cursor.
408
 *
409
 * PUBLIC: int cl_move(SCR *, size_t, size_t);
410
 */
411
int
412
cl_move(SCR *sp, size_t lno, size_t cno)
413
{
414
	/* See the comment in cl_cursor. */
415
	if (move(RLNO(sp, lno), cno) == ERR) {
416
		msgq(sp, M_ERR,
417
		    "Error: move: l(%u) c(%u) o(%u)", lno, cno, sp->woff);
418
		return (1);
419
	}
420
	return (0);
421
}
422
423
/*
424
 * cl_refresh --
425
 *	Refresh the screen.
426
 *
427
 * PUBLIC: int cl_refresh(SCR *, int);
428
 */
429
int
430
cl_refresh(SCR *sp, int repaint)
431
{
432
	CL_PRIVATE *clp;
433
434
	clp = CLP(sp);
435
436
	/*
437
	 * If we received a killer signal, we're done, there's no point
438
	 * in refreshing the screen.
439
	 */
440
	if (clp->killersig)
441
		return (0);
442
443
	/*
444
	 * If repaint is set, the editor is telling us that we don't know
445
	 * what's on the screen, so we have to repaint from scratch.
446
	 *
447
	 * In the curses library, doing wrefresh(curscr) is okay, but the
448
	 * screen flashes when we then apply the refresh() to bring it up
449
	 * to date.  So, use clearok().
450
	 */
451
	if (repaint)
452
		clearok(curscr, 1);
453
	return (refresh() == ERR);
454
}
455
456
/*
457
 * cl_rename --
458
 *	Rename the file.
459
 *
460
 * PUBLIC: int cl_rename(SCR *, char *, int);
461
 */
462
int
463
cl_rename(SCR *sp, char *name, int on)
464
{
465
	GS *gp;
466
	CL_PRIVATE *clp;
467
	char *ttype;
468
469
	gp = sp->gp;
470
	clp = CLP(sp);
471
472
	ttype = OG_STR(gp, GO_TERM);
473
474
	/*
475
	 * XXX
476
	 * We can only rename windows for xterm.
477
	 */
478
	if (on) {
479
		if (F_ISSET(clp, CL_RENAME_OK) &&
480
		    !strncmp(ttype, "xterm", sizeof("xterm") - 1)) {
481
			F_SET(clp, CL_RENAME);
482
			(void)printf(XTERM_RENAME, name);
483
			(void)fflush(stdout);
484
		}
485
	} else
486
		if (F_ISSET(clp, CL_RENAME)) {
487
			F_CLR(clp, CL_RENAME);
488
			(void)printf(XTERM_RENAME, ttype);
489
			(void)fflush(stdout);
490
		}
491
	return (0);
492
}
493
494
/*
495
 * cl_suspend --
496
 *	Suspend a screen.
497
 *
498
 * PUBLIC: int cl_suspend(SCR *, int *);
499
 */
500
int
501
cl_suspend(SCR *sp, int *allowedp)
502
{
503
	struct termios t;
504
	CL_PRIVATE *clp;
505
	size_t oldy, oldx;
506
	int changed;
507
508
	clp = CLP(sp);
509
	*allowedp = 1;
510
511
	/*
512
	 * The ex implementation of this function isn't needed by screens not
513
	 * supporting ex commands that require full terminal canonical mode
514
	 * (e.g. :suspend).
515
	 *
516
	 * The vi implementation of this function isn't needed by screens not
517
	 * supporting vi process suspension, i.e. any screen that isn't backed
518
	 * by a UNIX shell.
519
	 *
520
	 * Setting allowedp to 0 will cause the editor to reject the command.
521
	 */
522
	if (F_ISSET(sp, SC_EX)) {
523
		/* Save the terminal settings, and restore the original ones. */
524
		if (F_ISSET(clp, CL_STDIN_TTY)) {
525
			(void)tcgetattr(STDIN_FILENO, &t);
526
			(void)tcsetattr(STDIN_FILENO,
527
			    TCSASOFT | TCSADRAIN, &clp->orig);
528
		}
529
530
		/* Stop the process group. */
531
		(void)kill(0, SIGTSTP);
532
533
		/* Time passes ... */
534
535
		/* Restore terminal settings. */
536
		if (F_ISSET(clp, CL_STDIN_TTY))
537
			(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
538
		return (0);
539
	}
540
541
	/*
542
	 * Move to the lower left-hand corner of the screen.
543
	 *
544
	 * XXX
545
	 * Not sure this is necessary in System V implementations, but it
546
	 * shouldn't hurt.
547
	 */
548
	getyx(stdscr, oldy, oldx);
549
	(void)move(LINES - 1, 0);
550
	(void)refresh();
551
552
	/*
553
	 * Temporarily end the screen.  System V introduced a semantic where
554
	 * endwin() could be restarted.  We use it because restarting curses
555
	 * from scratch often fails in System V.
556
	 */
557
558
	/* Restore the cursor keys to normal mode. */
559
	(void)keypad(stdscr, FALSE);
560
561
	/* Restore the window name. */
562
	(void)cl_rename(sp, NULL, 0);
563
564
	(void)endwin();
565
566
	/*
567
	 * XXX
568
	 * Restore the original terminal settings.  This is bad -- the
569
	 * reset can cause character loss from the tty queue.  However,
570
	 * we can't call endwin() in BSD curses implementations, and too
571
	 * many System V curses implementations don't get it right.
572
	 */
573
	(void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig);
574
575
	/* Stop the process group. */
576
	(void)kill(0, SIGTSTP);
577
578
	/* Time passes ... */
579
580
	/*
581
	 * If we received a killer signal, we're done.  Leave everything
582
	 * unchanged.  In addition, the terminal has already been reset
583
	 * correctly, so leave it alone.
584
	 */
585
	if (clp->killersig) {
586
		F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
587
		return (0);
588
	}
589
590
	/* Set the window name. */
591
	(void)cl_rename(sp, sp->frp->name, 1);
592
593
	/* Put the cursor keys into application mode. */
594
	(void)keypad(stdscr, TRUE);
595
596
	/* Refresh and repaint the screen. */
597
	(void)move(oldy, oldx);
598
	(void)cl_refresh(sp, 1);
599
600
	/* If the screen changed size, set the SIGWINCH bit. */
601
	if (cl_ssize(sp, 1, NULL, NULL, &changed))
602
		return (1);
603
	if (changed)
604
		F_SET(CLP(sp), CL_SIGWINCH);
605
606
	return (0);
607
}
608
609
/*
610
 * cl_usage --
611
 *	Print out the curses usage messages.
612
 *
613
 * PUBLIC: void cl_usage(void);
614
 */
615
void
616
cl_usage()
617
{
618
	switch (pmode) {
619
	case MODE_EX:
620
		(void)fprintf(stderr, "usage: "
621
		    "ex [-FRrSsv] [-c cmd] [-t tag] [-w size] [file ...]\n");
622
		break;
623
	case MODE_VI:
624
		(void)fprintf(stderr, "usage: "
625
		    "vi [-eFRrS] [-c cmd] [-t tag] [-w size] [file ...]\n");
626
		break;
627
	case MODE_VIEW:
628
		(void)fprintf(stderr, "usage: "
629
		    "view [-eFrS] [-c cmd] [-t tag] [-w size] [file ...]\n");
630
		break;
631
	}
632
}
633
634
#ifdef DEBUG
635
/*
636
 * gdbrefresh --
637
 *	Stub routine so can flush out curses screen changes using gdb.
638
 */
639
int
640
gdbrefresh()
641
{
642
	refresh();
643
	return (0);		/* XXX Convince gdb to run it. */
644
}
645
#endif