POSIX 1003.2B/D9 symbolic links
[unix-history] / usr / src / usr.bin / ex / ex_v.c
CommitLineData
2791ff57 1/*-
eb035710
KB
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
2791ff57
KB
4 *
5 * %sccs.include.proprietary.c%
19d73a0e
DF
6 */
7
8#ifndef lint
eb035710 9static char sccsid[] = "@(#)ex_v.c 8.1 (Berkeley) %G%";
2791ff57 10#endif /* not lint */
19d73a0e 11
59ae3464
MH
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
2de97448 59jmp_buf venv;
b61c5edc 60void winch();
2de97448 61
59ae3464
MH
62/*
63 * Enter open mode
64 */
3c7b865a
MH
65#ifdef u370
66char atube[TUBESIZE+LBSIZE];
67#endif
59ae3464
MH
68oop()
69{
70 register char *ic;
3c7b865a 71#ifndef u370
59ae3464 72 char atube[TUBESIZE + LBSIZE];
3c7b865a 73#endif
299f2784 74 ttymode f; /* mjm: was register */
59ae3464 75
5a6c967e 76 if (setjmp(venv)) {
2de97448
JB
77 setsize();
78 initev = (char *)0;
79 inopen = 0;
80 addr1 = addr2 = dot;
81 }
5a6c967e 82#ifdef SIGWINCH
2de97448 83 (void)signal(SIGWINCH, winch);
5a6c967e 84#endif
59ae3464
MH
85 ovbeg();
86 if (peekchar() == '/') {
5a6c967e 87 ignore(compile(ex_getchar(), 1));
59ae3464
MH
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);
5a6c967e 141#ifdef SIGWINCH
2de97448 142 (void)signal(SIGWINCH, SIG_DFL);
5a6c967e 143#endif
59ae3464
MH
144}
145
146ovbeg()
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
160ovend(f)
d266c416 161 ttymode f;
59ae3464
MH
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 */
182vop()
183{
184 register int c;
3c7b865a 185#ifndef u370
59ae3464 186 char atube[TUBESIZE + LBSIZE];
3c7b865a 187#endif
299f2784 188 ttymode f; /* mjm: was register */
59ae3464
MH
189
190 if (!CA && UP == NOSTR) {
191 if (initev) {
192toopen:
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 }
d266c416
MH
210 if (NS && !SF) {
211 if (initev)
212 goto toopen;
213 error("Visual requires scrolling");
214 }
5a6c967e 215 if (setjmp(venv)) {
2de97448
JB
216 setsize();
217 initev = (char *)0;
218 inopen = 0;
219 addr1 = addr2 = dot;
220 }
5a6c967e 221#ifdef SIGWINCH
2de97448 222 (void)signal(SIGWINCH, winch);
5a6c967e 223#endif
59ae3464
MH
224 ovbeg();
225 bastate = VISUAL;
226 c = 0;
227 if (any(peekchar(), "+-^."))
5a6c967e 228 c = ex_getchar();
59ae3464
MH
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);
5a6c967e 246#ifdef SIGWINCH
2de97448 247 (void)signal(SIGWINCH, SIG_DFL);
5a6c967e 248#endif
59ae3464
MH
249}
250
251/*
252 * Hack to allow entry to visual with
253 * empty buffer since routines internally
254 * demand at least one line.
255 */
256fixzero()
257{
258
259 if (dol == zero) {
260 register bool ochng = chng;
261
262 vdoappend("");
263 if (!ochng)
5a6c967e 264 ex_sync();
59ae3464
MH
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 */
283savevis()
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 */
298undvis()
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;
d266c416
MH
310 if (undadot <= zero || undadot > dol)
311 undadot = zero+1;
59ae3464
MH
312}
313
314/*
315 * Set the window parameters based on the base state bastate
316 * and the available buffer space.
317 */
318setwind()
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;
5a6c967e 331 ex_ZERO = 0;
59ae3464
MH
332 holdcm++;
333 break;
334
335 case CRTOPEN:
336 basWTOP = LINES - 2;
337 /* fall into */
338
339 case VISUAL:
5a6c967e
CH
340 ex_ZERO = LINES - TUBESIZE / WCOLS;
341 if (ex_ZERO < 0)
342 ex_ZERO = 0;
343 if (ex_ZERO > basWTOP)
59ae3464
MH
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 */
357vok(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");
5a6c967e 366 if (WLINES >= TUBELINES || WCOLS * (WECHO - ex_ZERO + 1) > TUBESIZE)
59ae3464
MH
367 error("Screen too large");
368
369 vtube0 = atube;
5a6c967e
CH
370 vclrbyte(atube, WCOLS * (WECHO - ex_ZERO + 1));
371 for (i = 0; i < ex_ZERO; i++)
887e3e0d 372 vtube[i] = (char *) 0;
59ae3464
MH
373 for (; i <= WECHO; i++)
374 vtube[i] = atube, atube += WCOLS;
375 for (; i < TUBELINES; i++)
887e3e0d 376 vtube[i] = (char *) 0;
59ae3464
MH
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;
5a6c967e 389 Peek_key = 0;
59ae3464 390 vcnt = vcline = 0;
5a6c967e
CH
391 if (ex_vSCROLL == 0)
392 ex_vSCROLL = (value(WINDOW)+1)/2; /* round up so dft=6,11 */
59ae3464
MH
393}
394
395#ifdef CBREAK
b61c5edc 396void
59ae3464
MH
397vintr()
398{
b3c5103a 399 extern jmp_buf readbuf;
47bdd628 400 extern int doingread;
59ae3464
MH
401
402 signal(SIGINT, vintr);
403 if (vcatch)
404 onintr();
405 ungetkey(ATTN);
406 draino();
47bdd628
SL
407 if (doingread) {
408 doingread = 0;
409 longjmp(readbuf, 1);
410 }
59ae3464
MH
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 */
418vsetsiz(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}
2de97448 433
5a6c967e 434#ifdef SIGWINCH
b61c5edc 435void
2de97448
JB
436winch()
437{
438 vsave();
5a6c967e 439 ignore(setty(normf));
2de97448
JB
440 longjmp(venv, 1);
441}
5a6c967e 442#endif