xref: /titanic_52/usr/src/cmd/vi/port/ex_v.c (revision 84ab085a13f931bc78e7415e7ce921dbaa14fcb3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 /* Copyright (c) 1981 Regents of the University of California */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #include "ex.h"
36 #include "ex_re.h"
37 #include "ex_tty.h"
38 #include "ex_vis.h"
39 
40 /*
41  * Entry points to open and visual from command mode processor.
42  * The open/visual code breaks down roughly as follows:
43  *
44  * ex_v.c	entry points, checking of terminal characteristics
45  *
46  * ex_vadj.c	logical screen control, use of intelligent operations
47  *		insert/delete line and coordination with screen image;
48  *		updating of screen after changes.
49  *
50  * ex_vget.c	input of single keys and reading of input lines
51  *		from the echo area, handling of \ escapes on input for
52  *		uppercase only terminals, handling of memory for repeated
53  *		commands and small saved texts from inserts and partline
54  *		deletes, notification of multi line changes in the echo
55  *		area.
56  *
57  * ex_vmain.c	main command decoding, some command processing.
58  *
59  * ex_voperate.c   decoding of operator/operand sequences and
60  *		contextual scans, implementation of word motions.
61  *
62  * ex_vops.c	major operator interfaces, undos, motions, deletes,
63  *		changes, opening new lines, shifts, replacements and yanks
64  *		coordinating logical and physical changes.
65  *
66  * ex_vops2.c	subroutines for operator interfaces in ex_vops.c,
67  *		insert mode, read input line processing at lowest level.
68  *
69  * ex_vops3.c	structured motion definitions of ( ) { } and [ ] operators,
70  *		indent for lisp routines, () and {} balancing.
71  *
72  * ex_vput.c	output routines, clearing, physical mapping of logical cursor
73  *		positioning, cursor motions, handling of insert character
74  *		and delete character functions of intelligent and unintelligent
75  *		terminals, visual mode tracing routines (for debugging),
76  *		control of screen image and its updating.
77  *
78  * ex_vwind.c	window level control of display, forward and backward rolls,
79  *		absolute motions, contextual displays, line depth determination
80  */
81 
82 void setsize();
83 void winch();
84 void vintr();
85 
86 wchar_t	atube[TUBESIZE];
87 jmp_buf	venv;
88 int windowchg;
89 int sigok;
90 
91 /* reinitialize window size after SIGWINCH */
92 void windowinit()
93 {
94 	windowchg = 0;
95 	setsize();
96 	if(value(vi_WINDOW) >= lines || options[vi_WINDOW].odefault == value(vi_WINDOW))
97 		value(vi_WINDOW) = lines -1;
98 	options[vi_WINDOW].odefault = lines - 1;
99 	if(options[vi_SCROLL].odefault == value(vi_SCROLL))
100 		value(vi_SCROLL) = value(vi_WINDOW)/2;
101 	options[vi_SCROLL].odefault = (lines - 1)/2;
102 	vsetsiz(value(vi_WINDOW));
103 	setwind();
104 	vok(atube, 1);
105 }
106 
107 void redraw()
108 {
109 	vsave();
110 	windowinit();
111 	vclear();
112 	vdirty(0, lines);
113 	if(state != VISUAL) {
114 		vclean();
115 		vmoveto(dot, cursor, 0);
116 	} else {
117 		vredraw(WTOP);
118 		vrepaint(cursor);
119 		vfixcurs();
120 	}
121 }
122 
123 /*ARGSUSED*/
124 void
125 #ifdef __STDC__
126 winch(int sig)
127 #else
128 winch(sig)
129 int sig;
130 #endif
131 {
132 	struct winsize jwin;
133 	register int l;
134 
135 	if(ioctl(0, TIOCGWINSZ, &jwin) != -1) {
136 #ifdef XPG4
137 		oldlines = jwin.ws_row;
138 		oldcolumns = jwin.ws_col;
139 #endif /* XPG4 */
140 		if (sigok) {
141 			if (columns != jwin.ws_col || lines != jwin.ws_row)
142 			    redraw();
143 		}
144 	}
145 	else
146 		windowchg++;
147 	(void)signal(SIGWINCH, winch);
148 }
149 
150 void
151 setsize()
152 {
153 	struct winsize jwin;
154 	register int l;
155 
156 	if(ioctl(0, TIOCGWINSZ, &jwin) != -1) {
157 		if (jwin.ws_col > 0)
158 			columns = jwin.ws_col;
159 		if (jwin.ws_row > 0)
160 			lines = jwin.ws_row;
161 	}
162 
163 #ifdef XPG4
164 	if (envlines != -1) {
165 		lines = envlines;
166 	}
167 
168 	if (envcolumns != -1) {
169 		columns = envcolumns;
170 	}
171 
172 	if (envlines != -1 || envcolumns != -1) {
173 		jwin.ws_row = lines;
174 		jwin.ws_col = columns;
175 
176 		if (ioctl(0, TIOCSWINSZ, &jwin) == -1) {
177 			jwin.ws_row = oldlines;
178 			jwin.ws_col = oldcolumns;
179 
180 			ioctl(0, TIOCSWINSZ, &jwin);
181 		}
182 	}
183 #endif /* XPG4 */
184 
185 	if (lines <= 1)
186 		lines = 24;
187 	l = lines;
188 	if (columns <= 4)
189 		columns = 1000;
190 	value(vi_WINDOW) = options[vi_WINDOW].odefault = l - 1;
191 }
192 
193 /*
194  * Enter open mode
195  */
196 oop()
197 {
198 	register unsigned char *ic;
199 	ttymode f;	/* was register */
200 	int resize;
201 
202 	windowchg = 0;
203 	(void)signal(SIGWINCH, winch);
204 	ovbeg();
205 	if (peekchar() == '/') {
206 		(void)vi_compile(getchar(), 1);
207 		savere(&scanre);
208 		if (execute(0, dot) == 0)
209 			error(value(vi_TERSE) ? gettext("Fail") :
210 gettext("Pattern not found on addressed line"));
211 		ic = (unsigned char *)loc1;
212 		if (ic > linebuf && *ic == 0)
213 			ic--;
214 	} else {
215 		getDOT();
216 		ic = vskipwh(linebuf);
217 	}
218 	donewline();
219 
220 	/*
221 	 * If overstrike then have to HARDOPEN
222 	 * else if can move cursor up off current line can use CRTOPEN (~~vi1)
223 	 * otherwise have to use ONEOPEN (like adm3)
224 	 */
225 	if (over_strike && !erase_overstrike)
226 		bastate = HARDOPEN;
227 	else if (cursor_address || cursor_up)
228 		bastate = CRTOPEN;
229 	else
230 		bastate = ONEOPEN;
231 	setwind();
232 
233 	/*
234 	 * To avoid bombing on glass-crt's when the line is too long
235 	 * pretend that such terminals are 160 columns wide.
236 	 * If a line is too wide for display, we will dynamically
237 	 * switch to hardcopy open mode.
238 	 */
239 	if (state != CRTOPEN)
240 		WCOLS = TUBECOLS;
241 	if (!inglobal)
242 		savevis();
243 	vok(atube, 0);
244 	if (state != CRTOPEN)
245 		columns = WCOLS;
246 	Outchar = vputchar;
247 	f = ostart();
248 	if (state == CRTOPEN) {
249 		if (outcol == UKCOL)
250 			outcol = 0;
251 		vmoveitup(1, 1);
252 	} else
253 		outline = destline = WBOT;
254 	vshow(dot, NOLINE);
255 	vnline(ic);
256 	vmain();
257 	if (state != CRTOPEN)
258 		vclean();
259 	Command = (unsigned char *)"open";
260 	ovend(f);
261 	(void)signal(SIGWINCH, SIG_DFL);
262 }
263 
264 ovbeg()
265 {
266 
267 	if (inopen)
268 		error(gettext("Recursive open/visual not allowed"));
269 	Vlines = lineDOL();
270 	fixzero();
271 	setdot();
272 	pastwh();
273 	dot = addr2;
274 }
275 
276 ovend(f)
277 	ttymode f;
278 {
279 
280 	splitw++;
281 	vgoto(WECHO, 0);
282 	vclreol();
283 	vgoto(WECHO, 0);
284 	holdcm = 0;
285 	splitw = 0;
286 	ostop(f);
287 	setoutt();
288 	undvis();
289 	columns = OCOLUMNS;
290 	inopen = 0;
291 	flusho();
292 	netchHAD(Vlines);
293 }
294 
295 /*
296  * Enter visual mode
297  */
298 vop()
299 {
300 	register int c;
301 	ttymode f;	/* was register */
302 	extern unsigned char termtype[];
303 
304 	if (!cursor_address && !cursor_up) {
305 		if (initev) {
306 toopen:
307 			if (generic_type)
308 				merror(gettext("I don't know what kind of terminal you are on - all I have is '%s'."), termtype);
309 			putNFL();
310 			merror(gettext("[Using open mode]"));
311 			putNFL();
312 			oop();
313 			return;
314 		}
315 		error(gettext("Visual needs addressable cursor or upline capability"));
316 	}
317 	if (over_strike && !erase_overstrike) {
318 		if (initev)
319 			goto toopen;
320 		error(gettext("Can't use visual on a terminal which overstrikes"));
321 	}
322 	if (!clear_screen) {
323 		if (initev)
324 			goto toopen;
325 		error(gettext("Visual requires clear screen capability"));
326 	}
327 	if (!scroll_forward) {
328 		if (initev)
329 			goto toopen;
330 		error(gettext("Visual requires scrolling"));
331 	}
332 	windowchg = 0;
333 	(void)signal(SIGWINCH, winch);
334 	ovbeg();
335 	bastate = VISUAL;
336 	c = 0;
337 	if (any(peekchar(), "+-^."))
338 		c = getchar();
339 	pastwh();
340 	vsetsiz(isdigit(peekchar()) ? getnum() : value(vi_WINDOW));
341 	setwind();
342 	donewline();
343 	vok(atube, 0);
344 	if (!inglobal)
345 		savevis();
346 	Outchar = vputchar;
347 	vmoving = 0;
348 	f = ostart();
349 	if (initev == 0) {
350 		vcontext(dot, c);
351 		vnline(NOSTR);
352 	}
353 	vmain();
354 	Command = (unsigned char *)"visual";
355 	ovend(f);
356 	(void)signal(SIGWINCH, SIG_DFL);
357 }
358 
359 /*
360  * Hack to allow entry to visual with
361  * empty buffer since routines internally
362  * demand at least one line.
363  */
364 fixzero()
365 {
366 
367 	if (dol == zero) {
368 		register bool ochng = chng;
369 
370 		vdoappend("");
371 		if (!ochng)
372 			sync();
373 		addr1 = addr2 = one;
374 	} else if (addr2 == zero)
375 		addr2 = one;
376 }
377 
378 /*
379  * Save lines before visual between unddol and truedol.
380  * Accomplish this by throwing away current [unddol,truedol]
381  * and then saving all the lines in the buffer and moving
382  * unddol back to dol.  Don't do this if in a global.
383  *
384  * If you do
385  *	g/xxx/vi.
386  * and then do a
387  *	:e xxxx
388  * at some point, and then quit from the visual and undo
389  * you get the old file back.  Somewhat weird.
390  */
391 savevis()
392 {
393 
394 	if (inglobal)
395 		return;
396 	truedol = unddol;
397 	saveall();
398 	unddol = dol;
399 	undkind = UNDNONE;
400 }
401 
402 /*
403  * Restore a sensible state after a visual/open, moving the saved
404  * stuff back to [unddol,dol], and killing the partial line kill indicators.
405  */
406 undvis()
407 {
408 
409 	if (ruptible)
410 		signal(SIGINT, onintr);
411 	squish();
412 	pkill[0] = pkill[1] = 0;
413 	unddol = truedol;
414 	unddel = zero;
415 	undap1 = one;
416 	undap2 = dol + 1;
417 	undkind = UNDALL;
418 	if (undadot <= zero || undadot > dol)
419 		undadot = zero+1;
420 }
421 
422 /*
423  * Set the window parameters based on the base state bastate
424  * and the available buffer space.
425  */
426 setwind()
427 {
428 
429 	WCOLS = columns;
430 	switch (bastate) {
431 
432 	case ONEOPEN:
433 		if (auto_right_margin)
434 			WCOLS--;
435 		/* fall into ... */
436 
437 	case HARDOPEN:
438 		basWTOP = WTOP = WBOT = WECHO = 0;
439 		ZERO = 0;
440 		holdcm++;
441 		break;
442 
443 	case CRTOPEN:
444 		basWTOP = lines - 2;
445 		/* fall into */
446 
447 	case VISUAL:
448 		ZERO = lines - TUBESIZE / WCOLS;
449 		if (ZERO < 0)
450 			ZERO = 0;
451 		if (ZERO > basWTOP)
452 			error(gettext("Screen too large for internal buffer"));
453 		WTOP = basWTOP; WBOT = lines - 2; WECHO = lines - 1;
454 		break;
455 	}
456 	state = bastate;
457 	basWLINES = WLINES = WBOT - WTOP + 1;
458 }
459 
460 /*
461  * Can we hack an open/visual on this terminal?
462  * If so, then divide the screen buffer up into lines,
463  * and initialize a bunch of state variables before we start.
464  */
465 static unsigned char vlinebuf[LBSIZE];
466 
467 vok(atube, undo)
468 	register wchar_t *atube;
469 {
470 	register int i;
471 	static int beenhere;
472 
473 	if (WCOLS == 1000)
474 		serror(gettext("Don't know enough about your terminal to use %s"),
475 			Command);
476 	if (WCOLS > TUBECOLS)
477 		error(gettext("Terminal too wide"));
478 	if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE)
479 		error(gettext("Screen too large"));
480 
481 	vtube0 = atube;
482 	if(beenhere)
483 		vclrbyte(atube, WCOLS * (WECHO - ZERO + 1));
484 	for (i = 0; i < ZERO; i++)
485 		vtube[i] = (wchar_t *) 0;
486 	for (; i <= WECHO; i++)
487 		vtube[i] = atube, atube += WCOLS;
488 	if(beenhere++) {
489 		for (; i < TUBELINES; i++)
490 			vtube[i] = (wchar_t *) 0;
491 	}
492 	vutmp = vlinebuf;
493 	if(!undo) {
494 		vundkind = VNONE;
495 		vUNDdot = 0;
496 	}
497 	OCOLUMNS = columns;
498 	inopen = 1;
499 #ifdef CBREAK
500 	signal(SIGINT, vintr);
501 #endif
502 	vmoving = 0;
503 	splitw = 0;
504 	doomed = 0;
505 	holdupd = 0;
506 	if(!undo)
507 		Peekkey = 0;
508 	vcnt = vcline = 0;
509 	if (vSCROLL == 0)
510 		vSCROLL = value(vi_SCROLL);
511 }
512 
513 #ifdef CBREAK
514 /*ARGSUSED*/
515 void
516 #ifdef __STDC__
517 vintr(int sig)
518 #else
519 vintr(sig)
520 int sig;
521 #endif
522 {
523 
524 	signal(SIGINT, vintr);
525 	if (vcatch)
526 		onintr(0);
527 	ungetkey(ATTN);
528 	draino();
529 }
530 #endif
531 
532 /*
533  * Set the size of the screen to size lines, to take effect the
534  * next time the screen is redrawn.
535  */
536 vsetsiz(size)
537 	int size;
538 {
539 	register int b;
540 
541 	if (bastate != VISUAL)
542 		return;
543 	b = lines - 1 - size;
544 	if (b >= lines - 1)
545 		b = lines - 2;
546 	if (b < 0)
547 		b = 0;
548 	basWTOP = b;
549 	basWLINES = WBOT - b + 1;
550 }
551