1 /*
2  * This code contains changes by
3  *      Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4  *
5  * Conditions 1, 2, and 4 and the no-warranty notice below apply
6  * to these changes.
7  *
8  *
9  * Copyright (c) 1980, 1993
10  * 	The Regents of the University of California.  All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  * 	This product includes software developed by the University of
23  * 	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *
41  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  *   Redistributions of source code and documentation must retain the
47  *    above copyright notice, this list of conditions and the following
48  *    disclaimer.
49  *   Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  *   All advertising materials mentioning features or use of this software
53  *    must display the following acknowledgement:
54  *      This product includes software developed or owned by Caldera
55  *      International, Inc.
56  *   Neither the name of Caldera International, Inc. nor the names of
57  *    other contributors may be used to endorse or promote products
58  *    derived from this software without specific prior written permission.
59  *
60  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64  * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65  * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72  */
73 
74 #ifndef	lint
75 #ifdef	DOSCCS
76 static char sccsid[] = "@(#)ex_v.c	1.17 (gritter) 11/27/04";
77 #endif
78 #endif
79 
80 /* from ex_v.c	7.8.1 (2.11BSD GTE) 12/9/94 */
81 
82 #include "ex.h"
83 #include "ex_re.h"
84 #include "ex_tty.h"
85 #include "ex_vis.h"
86 
87 /*
88  * Entry points to open and visual from command mode processor.
89  * The open/visual code breaks down roughly as follows:
90  *
91  * ex_v.c	entry points, checking of terminal characteristics
92  *
93  * ex_vadj.c	logical screen control, use of intelligent operations
94  *		insert/delete line and coordination with screen image;
95  *		updating of screen after changes.
96  *
97  * ex_vget.c	input of single keys and reading of input lines
98  *		from the echo area, handling of memory for repeated
99  *		commands and small saved texts from inserts and partline
100  *		deletes, notification of multi line changes in the echo
101  *		area.
102  *
103  * ex_vmain.c	main command decoding, some command processing.
104  *
105  * ex_voperate.c   decoding of operator/operand sequences and
106  *		contextual scans, implementation of word motions.
107  *
108  * ex_vops.c	major operator interfaces, undos, motions, deletes,
109  *		changes, opening new lines, shifts, replacements and yanks
110  *		coordinating logical and physical changes.
111  *
112  * ex_vops2.c	subroutines for operator interfaces in ex_vops.c,
113  *		insert mode, read input line processing at lowest level.
114  *
115  * ex_vops3.c	structured motion definitions of ( ) { } and [ ] operators,
116  *		indent for lisp routines, () and {} balancing.
117  *
118  * ex_vput.c	output routines, clearing, physical mapping of logical cursor
119  *		positioning, cursor motions, handling of insert character
120  *		and delete character functions of intelligent and unintelligent
121  *		terminals, visual mode tracing routines (for debugging),
122  *		control of screen image and its updating.
123  *
124  * ex_vwind.c	window level control of display, forward and backward rolls,
125  *		absolute motions, contextual displays, line depth determination
126  */
127 
128 JMP_BUF venv;
129 
130 /*
131  * Enter open mode
132  */
133 #ifdef u370
134 cell	atube[TUBESIZE+LBSIZE];
135 #endif
136 void
oop(void)137 oop(void)
138 {
139 	register char *ic;
140 #ifndef u370
141 	cell atube[TUBESIZE + LBSIZE];
142 #endif
143 	struct termios f;	/* mjm: was register */
144 	int resize;
145 
146 	resize = SETJMP(venv);
147 	if (resize) {
148 		setsize();
149 		initev = (char *)0;
150 		inopen = 0;
151 		addr1 = addr2 = dot;
152 	}
153 #ifdef	SIGWINCH
154 	signal(SIGWINCH, onwinch);
155 #endif
156 	ovbeg();
157 	if (peekchar() == '/') {
158 		ignore(compile(getchar(), 1));
159 		savere(&scanre);
160 		if (execute(0, dot) == 0)
161 			error(catgets(catd, 1, 207,
162 				"Fail|Pattern not found on addressed line"));
163 		ic = loc1;
164 		if (ic > linebuf && *ic == 0)
165 			ic--;
166 	} else {
167 		getDOT();
168 		ic = vskipwh(linebuf);
169 	}
170 	newline();
171 
172 	/*
173 	 * If overstrike then have to HARDOPEN
174 	 * else if can move cursor up off current line can use CRTOPEN (~~vi1)
175 	 * otherwise (ugh) have to use ONEOPEN (like adm3)
176 	 */
177 	if (OS && !EO)
178 		bastate = HARDOPEN;
179 	else if (CA || UP)
180 		bastate = CRTOPEN;
181 	else
182 		bastate = ONEOPEN;
183 	setwind();
184 
185 	/*
186 	 * To avoid bombing on glass-crt's when the line is too long
187 	 * pretend that such terminals are 160 columns wide.
188 	 * If a line is too wide for display, we will dynamically
189 	 * switch to hardcopy open mode.
190 	 */
191 	if (state != CRTOPEN)
192 		WCOLS = TUBECOLS;
193 	if (!inglobal)
194 		savevis();
195 	vok(atube);
196 	if (state != CRTOPEN)
197 		TCOLUMNS = WCOLS;
198 	Outchar = vputchar;
199 	f = ostart();
200 	if (state == CRTOPEN) {
201 		if (outcol == UKCOL)
202 			outcol = 0;
203 		vmoveitup(1, 1);
204 	} else
205 		outline = destline = WBOT;
206 	vshow(dot, NOLINE);
207 	vnline(ic);
208 	vmain();
209 	if (state != CRTOPEN)
210 		vclean();
211 	Command = "open";
212 	ovend(f);
213 #ifdef	SIGWINCH
214 	signal(SIGWINCH, SIG_DFL);
215 #endif
216 }
217 
218 void
ovbeg(void)219 ovbeg(void)
220 {
221 
222 	if (!value(OPEN))
223 		error(catgets(catd, 1, 208,
224 			"Can't use open/visual unless open option is set"));
225 	if (inopen)
226 		error(catgets(catd, 1, 209,
227 					"Recursive open/visual not allowed"));
228 	Vlines = lineDOL();
229 	fixzero();
230 	setdot();
231 	pastwh();
232 	dot = addr2;
233 }
234 
235 void
ovend(struct termios f)236 ovend(struct termios f)
237 {
238 
239 	splitw++;
240 	vgoto(WECHO, 0);
241 	vclreol();
242 	vgoto(WECHO, 0);
243 	holdcm = 0;
244 	splitw = 0;
245 	ostop(f);
246 	setoutt();
247 	undvis();
248 	TCOLUMNS = OCOLUMNS;
249 	inopen = 0;
250 	flusho();
251 	netchHAD(Vlines);
252 }
253 
254 /*
255  * Enter visual mode
256  */
257 void
vop(void)258 vop(void)
259 {
260 	register int c;
261 #ifndef u370
262 	cell atube[TUBESIZE + LBSIZE];
263 #endif
264 	struct termios f;	/* mjm: was register */
265 	int resize;
266 
267 	if (!CA && UP == NOSTR) {
268 		if (initev) {
269 toopen:
270 			merror(catgets(catd, 1, 210, "[Using open mode]"));
271 			putNFL();
272 			oop();
273 			return;
274 		}
275 		error(catgets(catd, 1, 211,
276 		"Visual needs addressible cursor or upline capability"));
277 	}
278 	if (OS && !EO) {
279 		if (initev)
280 			goto toopen;
281 		error(catgets(catd, 1, 212,
282 			"Can't use visual on a terminal which overstrikes"));
283 	}
284 	if (!CL) {
285 		if (initev)
286 			goto toopen;
287 		error(catgets(catd, 1, 213,
288 			"Visual requires clear screen capability"));
289 	}
290 	if (NS && !SF) {
291 		if (initev)
292 			goto toopen;
293 		error(catgets(catd, 1, 214, "Visual requires scrolling"));
294 	}
295 	resize = SETJMP(venv);
296 	if (resize) {
297 		setsize();
298 		initev = (char *)0;
299 		inopen = 0;
300 		addr1 = addr2 = dot;
301 	}
302 #ifdef	SIGWINCH
303 	signal(SIGWINCH, onwinch);
304 #endif
305 	ovbeg();
306 	bastate = VISUAL;
307 	c = 0;
308 	if (any(peekchar(), "+-^."))
309 		c = getchar();
310 	pastwh();
311 	vsetsiz(isdigit(peekchar()) ? getnum() : value(WINDOW));
312 	setwind();
313 	newline();
314 	vok(atube);
315 	if (!inglobal)
316 		savevis();
317 	Outchar = vputchar;
318 	vmoving = 0;
319 	f = ostart();
320 	if (initev == 0) {
321 		vcontext(dot, c);
322 		vnline(NOSTR);
323 	}
324 	vmain();
325 	Command = "visual";
326 	ovend(f);
327 #ifdef	SIGWINCH
328 	signal(SIGWINCH, SIG_DFL);
329 #endif
330 }
331 
332 /*
333  * Hack to allow entry to visual with
334  * empty buffer since routines internally
335  * demand at least one line.
336  */
337 void
fixzero(void)338 fixzero(void)
339 {
340 
341 	if (dol == zero) {
342 		register bool ochng = chng;
343 
344 		vdoappend("");
345 		if (!ochng)
346 			synced();
347 		fixedzero++;
348 		addr1 = addr2 = one;
349 	} else if (addr2 == zero)
350 		addr2 = one;
351 }
352 
353 /*
354  * Save lines before visual between unddol and truedol.
355  * Accomplish this by throwing away current [unddol,truedol]
356  * and then saving all the lines in the buffer and moving
357  * unddol back to dol.  Don't do this if in a global.
358  *
359  * If you do
360  *	g/xxx/vi.
361  * and then do a
362  *	:e xxxx
363  * at some point, and then quit from the visual and undo
364  * you get the old file back.  Somewhat weird.
365  */
366 void
savevis(void)367 savevis(void)
368 {
369 
370 	if (inglobal)
371 		return;
372 	truedol = unddol;
373 	saveall();
374 	unddol = dol;
375 	undkind = UNDNONE;
376 }
377 
378 /*
379  * Restore a sensible state after a visual/open, moving the saved
380  * stuff back to [unddol,dol], and killing the partial line kill indicators.
381  */
382 void
undvis(void)383 undvis(void)
384 {
385 
386 	if (ruptible)
387 		signal(SIGINT, onintr);
388 	squish();
389 	pkill[0] = pkill[1] = 0;
390 	unddol = truedol;
391 	unddel = zero;
392 	undap1 = one;
393 	undap2 = dol + 1;
394 	undkind = UNDALL;
395 	if (undadot <= zero || undadot > dol)
396 		undadot = zero+1;
397 }
398 
399 /*
400  * Set the window parameters based on the base state bastate
401  * and the available buffer space.
402  */
403 void
setwind(void)404 setwind(void)
405 {
406 
407 	WCOLS = TCOLUMNS;
408 	switch (bastate) {
409 
410 	case ONEOPEN:
411 		if (AM)
412 			WCOLS--;
413 		/* fall into ... */
414 
415 	case HARDOPEN:
416 		basWTOP = WTOP = WBOT = WECHO = 0;
417 		ZERO = 0;
418 		holdcm++;
419 		break;
420 
421 	case CRTOPEN:
422 		basWTOP = TLINES - 2;
423 		/* fall into */
424 
425 	case VISUAL:
426 		ZERO = TLINES - TUBESIZE / WCOLS;
427 		if (ZERO < 0)
428 			ZERO = 0;
429 		if (ZERO > basWTOP)
430 			error(catgets(catd, 1, 215,
431 				"Screen too large for internal buffer"));
432 		WTOP = basWTOP; WBOT = TLINES - 2; WECHO = TLINES - 1;
433 		break;
434 	}
435 	state = bastate;
436 	basWLINES = WLINES = WBOT - WTOP + 1;
437 }
438 
439 /*
440  * Can we hack an open/visual on this terminal?
441  * If so, then divide the screen buffer up into lines,
442  * and initialize a bunch of state variables before we start.
443  */
444 void
vok(register cell * atube)445 vok(register cell *atube)
446 {
447 	register int i;
448 
449 	if (WCOLS == 1000)
450 		serror(catgets(catd, 1, 216,
451 		"Don't know enough about your terminal to use %s"), Command);
452 	if (WCOLS > TUBECOLS)
453 		error(catgets(catd, 1, 217, "Terminal too wide"));
454 	if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE)
455 		error(catgets(catd, 1, 218, "Screen too large"));
456 
457 	vtube0 = atube;
458 	vclrcell(atube, WCOLS * (WECHO - ZERO + 1));
459 	for (i = 0; i < ZERO; i++)
460 		vtube[i] = (cell *) 0;
461 	for (; i <= WECHO; i++)
462 		vtube[i] = atube, atube += WCOLS;
463 	for (; i < TUBELINES; i++)
464 		vtube[i] = (cell *) 0;
465 	vutmp = (char *)atube;
466 	vundkind = VNONE;
467 	vUNDdot = 0;
468 	OCOLUMNS = TCOLUMNS;
469 	inopen = 1;
470 	signal(SIGINT, vintr);
471 	vmoving = 0;
472 	splitw = 0;
473 	doomed = 0;
474 	holdupd = 0;
475 	Peekkey = 0;
476 	vcnt = vcline = 0;
477 	if (vSCROLL == 0)
478 		vSCROLL = value(SCROLL);
479 		/*old vSCROLL = (value(WINDOW)+1)/2;*//* round up so dft=6,11 */
480 }
481 
482 void
vintr(int signum)483 vintr(int signum)
484 {
485 	extern JMP_BUF readbuf;
486 	extern int doingread;
487 
488 	signal(SIGINT, vintr);
489 	if (vcatch)
490 		onintr(SIGINT);
491 	ungetkey(ATTN);
492 	draino();
493 	if (doingread) {
494 		doingread = 0;
495 		LONGJMP(readbuf, 1);
496 	}
497 }
498 
499 /*
500  * Set the size of the screen to size lines, to take effect the
501  * next time the screen is redrawn.
502  */
503 void
vsetsiz(int size)504 vsetsiz(int size)
505 {
506 	register int b;
507 
508 	if (bastate != VISUAL)
509 		return;
510 	b = TLINES - 1 - size;
511 	if (b >= TLINES - 1)
512 		b = TLINES - 2;
513 	if (b < 0)
514 		b = 0;
515 	basWTOP = b;
516 	basWLINES = WBOT - b + 1;
517 }
518 
519 #ifdef	SIGWINCH
520 void
onwinch(int signum)521 onwinch(int signum)
522 {
523 	vsave();
524 	setty(normf);
525 	LONGJMP(venv, 1);
526 }
527 #endif
528