xref: /original-bsd/usr.bin/ex/ex_v.c (revision 3705696b)
1 /*-
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)ex_v.c	8.1 (Berkeley) 06/09/93";
10 #endif /* not lint */
11 
12 #include "ex.h"
13 #include "ex_re.h"
14 #include "ex_tty.h"
15 #include "ex_vis.h"
16 
17 /*
18  * Entry points to open and visual from command mode processor.
19  * The open/visual code breaks down roughly as follows:
20  *
21  * ex_v.c	entry points, checking of terminal characteristics
22  *
23  * ex_vadj.c	logical screen control, use of intelligent operations
24  *		insert/delete line and coordination with screen image;
25  *		updating of screen after changes.
26  *
27  * ex_vget.c	input of single keys and reading of input lines
28  *		from the echo area, handling of \ escapes on input for
29  *		uppercase only terminals, handling of memory for repeated
30  *		commands and small saved texts from inserts and partline
31  *		deletes, notification of multi line changes in the echo
32  *		area.
33  *
34  * ex_vmain.c	main command decoding, some command processing.
35  *
36  * ex_voperate.c   decoding of operator/operand sequences and
37  *		contextual scans, implementation of word motions.
38  *
39  * ex_vops.c	major operator interfaces, undos, motions, deletes,
40  *		changes, opening new lines, shifts, replacements and yanks
41  *		coordinating logical and physical changes.
42  *
43  * ex_vops2.c	subroutines for operator interfaces in ex_vops.c,
44  *		insert mode, read input line processing at lowest level.
45  *
46  * ex_vops3.c	structured motion definitions of ( ) { } and [ ] operators,
47  *		indent for lisp routines, () and {} balancing.
48  *
49  * ex_vput.c	output routines, clearing, physical mapping of logical cursor
50  *		positioning, cursor motions, handling of insert character
51  *		and delete character functions of intelligent and unintelligent
52  *		terminals, visual mode tracing routines (for debugging),
53  *		control of screen image and its updating.
54  *
55  * ex_vwind.c	window level control of display, forward and backward rolls,
56  *		absolute motions, contextual displays, line depth determination
57  */
58 
59 jmp_buf venv;
60 void	winch();
61 
62 /*
63  * Enter open mode
64  */
65 #ifdef u370
66 char	atube[TUBESIZE+LBSIZE];
67 #endif
68 oop()
69 {
70 	register char *ic;
71 #ifndef u370
72 	char atube[TUBESIZE + LBSIZE];
73 #endif
74 	ttymode f;	/* mjm: was register */
75 
76 	if (setjmp(venv)) {
77 		setsize();
78 		initev = (char *)0;
79 		inopen = 0;
80 		addr1 = addr2 = dot;
81 	}
82 #ifdef	SIGWINCH
83 	(void)signal(SIGWINCH, winch);
84 #endif
85 	ovbeg();
86 	if (peekchar() == '/') {
87 		ignore(compile(ex_getchar(), 1));
88 		savere(scanre);
89 		if (execute(0, dot) == 0)
90 			error("Fail|Pattern not found on addressed line");
91 		ic = loc1;
92 		if (ic > linebuf && *ic == 0)
93 			ic--;
94 	} else {
95 		getDOT();
96 		ic = vskipwh(linebuf);
97 	}
98 	newline();
99 
100 	/*
101 	 * If overstrike then have to HARDOPEN
102 	 * else if can move cursor up off current line can use CRTOPEN (~~vi1)
103 	 * otherwise (ugh) have to use ONEOPEN (like adm3)
104 	 */
105 	if (OS && !EO)
106 		bastate = HARDOPEN;
107 	else if (CA || UP)
108 		bastate = CRTOPEN;
109 	else
110 		bastate = ONEOPEN;
111 	setwind();
112 
113 	/*
114 	 * To avoid bombing on glass-crt's when the line is too long
115 	 * pretend that such terminals are 160 columns wide.
116 	 * If a line is too wide for display, we will dynamically
117 	 * switch to hardcopy open mode.
118 	 */
119 	if (state != CRTOPEN)
120 		WCOLS = TUBECOLS;
121 	if (!inglobal)
122 		savevis();
123 	vok(atube);
124 	if (state != CRTOPEN)
125 		COLUMNS = WCOLS;
126 	Outchar = vputchar;
127 	f = ostart();
128 	if (state == CRTOPEN) {
129 		if (outcol == UKCOL)
130 			outcol = 0;
131 		vmoveitup(1, 1);
132 	} else
133 		outline = destline = WBOT;
134 	vshow(dot, NOLINE);
135 	vnline(ic);
136 	vmain();
137 	if (state != CRTOPEN)
138 		vclean();
139 	Command = "open";
140 	ovend(f);
141 #ifdef	SIGWINCH
142 	(void)signal(SIGWINCH, SIG_DFL);
143 #endif
144 }
145 
146 ovbeg()
147 {
148 
149 	if (!value(OPEN))
150 		error("Can't use open/visual unless open option is set");
151 	if (inopen)
152 		error("Recursive open/visual not allowed");
153 	Vlines = lineDOL();
154 	fixzero();
155 	setdot();
156 	pastwh();
157 	dot = addr2;
158 }
159 
160 ovend(f)
161 	ttymode f;
162 {
163 
164 	splitw++;
165 	vgoto(WECHO, 0);
166 	vclreol();
167 	vgoto(WECHO, 0);
168 	holdcm = 0;
169 	splitw = 0;
170 	ostop(f);
171 	setoutt();
172 	undvis();
173 	COLUMNS = OCOLUMNS;
174 	inopen = 0;
175 	flusho();
176 	netchHAD(Vlines);
177 }
178 
179 /*
180  * Enter visual mode
181  */
182 vop()
183 {
184 	register int c;
185 #ifndef u370
186 	char atube[TUBESIZE + LBSIZE];
187 #endif
188 	ttymode f;	/* mjm: was register */
189 
190 	if (!CA && UP == NOSTR) {
191 		if (initev) {
192 toopen:
193 			merror("[Using open mode]");
194 			putNFL();
195 			oop();
196 			return;
197 		}
198 		error("Visual needs addressible cursor or upline capability");
199 	}
200 	if (OS && !EO) {
201 		if (initev)
202 			goto toopen;
203 		error("Can't use visual on a terminal which overstrikes");
204 	}
205 	if (!CL) {
206 		if (initev)
207 			goto toopen;
208 		error("Visual requires clear screen capability");
209 	}
210 	if (NS && !SF) {
211 		if (initev)
212 			goto toopen;
213 		error("Visual requires scrolling");
214 	}
215 	if (setjmp(venv)) {
216 		setsize();
217 		initev = (char *)0;
218 		inopen = 0;
219 		addr1 = addr2 = dot;
220 	}
221 #ifdef	SIGWINCH
222 	(void)signal(SIGWINCH, winch);
223 #endif
224 	ovbeg();
225 	bastate = VISUAL;
226 	c = 0;
227 	if (any(peekchar(), "+-^."))
228 		c = ex_getchar();
229 	pastwh();
230 	vsetsiz(isdigit(peekchar()) ? getnum() : value(WINDOW));
231 	setwind();
232 	newline();
233 	vok(atube);
234 	if (!inglobal)
235 		savevis();
236 	Outchar = vputchar;
237 	vmoving = 0;
238 	f = ostart();
239 	if (initev == 0) {
240 		vcontext(dot, c);
241 		vnline(NOSTR);
242 	}
243 	vmain();
244 	Command = "visual";
245 	ovend(f);
246 #ifdef	SIGWINCH
247 	(void)signal(SIGWINCH, SIG_DFL);
248 #endif
249 }
250 
251 /*
252  * Hack to allow entry to visual with
253  * empty buffer since routines internally
254  * demand at least one line.
255  */
256 fixzero()
257 {
258 
259 	if (dol == zero) {
260 		register bool ochng = chng;
261 
262 		vdoappend("");
263 		if (!ochng)
264 			ex_sync();
265 		addr1 = addr2 = one;
266 	} else if (addr2 == zero)
267 		addr2 = one;
268 }
269 
270 /*
271  * Save lines before visual between unddol and truedol.
272  * Accomplish this by throwing away current [unddol,truedol]
273  * and then saving all the lines in the buffer and moving
274  * unddol back to dol.  Don't do this if in a global.
275  *
276  * If you do
277  *	g/xxx/vi.
278  * and then do a
279  *	:e xxxx
280  * at some point, and then quit from the visual and undo
281  * you get the old file back.  Somewhat weird.
282  */
283 savevis()
284 {
285 
286 	if (inglobal)
287 		return;
288 	truedol = unddol;
289 	saveall();
290 	unddol = dol;
291 	undkind = UNDNONE;
292 }
293 
294 /*
295  * Restore a sensible state after a visual/open, moving the saved
296  * stuff back to [unddol,dol], and killing the partial line kill indicators.
297  */
298 undvis()
299 {
300 
301 	if (ruptible)
302 		signal(SIGINT, onintr);
303 	squish();
304 	pkill[0] = pkill[1] = 0;
305 	unddol = truedol;
306 	unddel = zero;
307 	undap1 = one;
308 	undap2 = dol + 1;
309 	undkind = UNDALL;
310 	if (undadot <= zero || undadot > dol)
311 		undadot = zero+1;
312 }
313 
314 /*
315  * Set the window parameters based on the base state bastate
316  * and the available buffer space.
317  */
318 setwind()
319 {
320 
321 	WCOLS = COLUMNS;
322 	switch (bastate) {
323 
324 	case ONEOPEN:
325 		if (AM)
326 			WCOLS--;
327 		/* fall into ... */
328 
329 	case HARDOPEN:
330 		basWTOP = WTOP = WBOT = WECHO = 0;
331 		ex_ZERO = 0;
332 		holdcm++;
333 		break;
334 
335 	case CRTOPEN:
336 		basWTOP = LINES - 2;
337 		/* fall into */
338 
339 	case VISUAL:
340 		ex_ZERO = LINES - TUBESIZE / WCOLS;
341 		if (ex_ZERO < 0)
342 			ex_ZERO = 0;
343 		if (ex_ZERO > basWTOP)
344 			error("Screen too large for internal buffer");
345 		WTOP = basWTOP; WBOT = LINES - 2; WECHO = LINES - 1;
346 		break;
347 	}
348 	state = bastate;
349 	basWLINES = WLINES = WBOT - WTOP + 1;
350 }
351 
352 /*
353  * Can we hack an open/visual on this terminal?
354  * If so, then divide the screen buffer up into lines,
355  * and initialize a bunch of state variables before we start.
356  */
357 vok(atube)
358 	register char *atube;
359 {
360 	register int i;
361 
362 	if (WCOLS == 1000)
363 		serror("Don't know enough about your terminal to use %s", Command);
364 	if (WCOLS > TUBECOLS)
365 		error("Terminal too wide");
366 	if (WLINES >= TUBELINES || WCOLS * (WECHO - ex_ZERO + 1) > TUBESIZE)
367 		error("Screen too large");
368 
369 	vtube0 = atube;
370 	vclrbyte(atube, WCOLS * (WECHO - ex_ZERO + 1));
371 	for (i = 0; i < ex_ZERO; i++)
372 		vtube[i] = (char *) 0;
373 	for (; i <= WECHO; i++)
374 		vtube[i] = atube, atube += WCOLS;
375 	for (; i < TUBELINES; i++)
376 		vtube[i] = (char *) 0;
377 	vutmp = atube;
378 	vundkind = VNONE;
379 	vUNDdot = 0;
380 	OCOLUMNS = COLUMNS;
381 	inopen = 1;
382 #ifdef CBREAK
383 	signal(SIGINT, vintr);
384 #endif
385 	vmoving = 0;
386 	splitw = 0;
387 	doomed = 0;
388 	holdupd = 0;
389 	Peek_key = 0;
390 	vcnt = vcline = 0;
391 	if (ex_vSCROLL == 0)
392 		ex_vSCROLL = (value(WINDOW)+1)/2; /* round up so dft=6,11 */
393 }
394 
395 #ifdef CBREAK
396 void
397 vintr()
398 {
399 	extern jmp_buf readbuf;
400 	extern int doingread;
401 
402 	signal(SIGINT, vintr);
403 	if (vcatch)
404 		onintr();
405 	ungetkey(ATTN);
406 	draino();
407 	if (doingread) {
408 		doingread = 0;
409 		longjmp(readbuf, 1);
410 	}
411 }
412 #endif
413 
414 /*
415  * Set the size of the screen to size lines, to take effect the
416  * next time the screen is redrawn.
417  */
418 vsetsiz(size)
419 	int size;
420 {
421 	register int b;
422 
423 	if (bastate != VISUAL)
424 		return;
425 	b = LINES - 1 - size;
426 	if (b >= LINES - 1)
427 		b = LINES - 2;
428 	if (b < 0)
429 		b = 0;
430 	basWTOP = b;
431 	basWLINES = WBOT - b + 1;
432 }
433 
434 #ifdef	SIGWINCH
435 void
436 winch()
437 {
438 	vsave();
439 	ignore(setty(normf));
440 	longjmp(venv, 1);
441 }
442 #endif
443