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