Must distinguish between "ambiguous" and "unknown" commands.
[unix-history] / usr / src / usr.bin / ex / ex_v.c
CommitLineData
19d73a0e
DF
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
5a6c967e 8static char *sccsid = "@(#)ex_v.c 7.9 (Berkeley) %G%";
19d73a0e
DF
9#endif not lint
10
59ae3464
MH
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
2de97448
JB
58jmp_buf venv;
59int winch();
60
59ae3464
MH
61/*
62 * Enter open mode
63 */
3c7b865a
MH
64#ifdef u370
65char atube[TUBESIZE+LBSIZE];
66#endif
59ae3464
MH
67oop()
68{
69 register char *ic;
3c7b865a 70#ifndef u370
59ae3464 71 char atube[TUBESIZE + LBSIZE];
3c7b865a 72#endif
299f2784 73 ttymode f; /* mjm: was register */
59ae3464 74
5a6c967e 75 if (setjmp(venv)) {
2de97448
JB
76 setsize();
77 initev = (char *)0;
78 inopen = 0;
79 addr1 = addr2 = dot;
80 }
5a6c967e 81#ifdef SIGWINCH
2de97448 82 (void)signal(SIGWINCH, winch);
5a6c967e 83#endif
59ae3464
MH
84 ovbeg();
85 if (peekchar() == '/') {
5a6c967e 86 ignore(compile(ex_getchar(), 1));
59ae3464
MH
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);
5a6c967e 140#ifdef SIGWINCH
2de97448 141 (void)signal(SIGWINCH, SIG_DFL);
5a6c967e 142#endif
59ae3464
MH
143}
144
145ovbeg()
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
159ovend(f)
d266c416 160 ttymode f;
59ae3464
MH
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 */
181vop()
182{
183 register int c;
3c7b865a 184#ifndef u370
59ae3464 185 char atube[TUBESIZE + LBSIZE];
3c7b865a 186#endif
299f2784 187 ttymode f; /* mjm: was register */
59ae3464
MH
188
189 if (!CA && UP == NOSTR) {
190 if (initev) {
191toopen:
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 }
d266c416
MH
209 if (NS && !SF) {
210 if (initev)
211 goto toopen;
212 error("Visual requires scrolling");
213 }
5a6c967e 214 if (setjmp(venv)) {
2de97448
JB
215 setsize();
216 initev = (char *)0;
217 inopen = 0;
218 addr1 = addr2 = dot;
219 }
5a6c967e 220#ifdef SIGWINCH
2de97448 221 (void)signal(SIGWINCH, winch);
5a6c967e 222#endif
59ae3464
MH
223 ovbeg();
224 bastate = VISUAL;
225 c = 0;
226 if (any(peekchar(), "+-^."))
5a6c967e 227 c = ex_getchar();
59ae3464
MH
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);
5a6c967e 245#ifdef SIGWINCH
2de97448 246 (void)signal(SIGWINCH, SIG_DFL);
5a6c967e 247#endif
59ae3464
MH
248}
249
250/*
251 * Hack to allow entry to visual with
252 * empty buffer since routines internally
253 * demand at least one line.
254 */
255fixzero()
256{
257
258 if (dol == zero) {
259 register bool ochng = chng;
260
261 vdoappend("");
262 if (!ochng)
5a6c967e 263 ex_sync();
59ae3464
MH
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 */
282savevis()
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 */
297undvis()
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;
d266c416
MH
309 if (undadot <= zero || undadot > dol)
310 undadot = zero+1;
59ae3464
MH
311}
312
313/*
314 * Set the window parameters based on the base state bastate
315 * and the available buffer space.
316 */
317setwind()
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;
5a6c967e 330 ex_ZERO = 0;
59ae3464
MH
331 holdcm++;
332 break;
333
334 case CRTOPEN:
335 basWTOP = LINES - 2;
336 /* fall into */
337
338 case VISUAL:
5a6c967e
CH
339 ex_ZERO = LINES - TUBESIZE / WCOLS;
340 if (ex_ZERO < 0)
341 ex_ZERO = 0;
342 if (ex_ZERO > basWTOP)
59ae3464
MH
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 */
356vok(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");
5a6c967e 365 if (WLINES >= TUBELINES || WCOLS * (WECHO - ex_ZERO + 1) > TUBESIZE)
59ae3464
MH
366 error("Screen too large");
367
368 vtube0 = atube;
5a6c967e
CH
369 vclrbyte(atube, WCOLS * (WECHO - ex_ZERO + 1));
370 for (i = 0; i < ex_ZERO; i++)
887e3e0d 371 vtube[i] = (char *) 0;
59ae3464
MH
372 for (; i <= WECHO; i++)
373 vtube[i] = atube, atube += WCOLS;
374 for (; i < TUBELINES; i++)
887e3e0d 375 vtube[i] = (char *) 0;
59ae3464
MH
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;
5a6c967e 388 Peek_key = 0;
59ae3464 389 vcnt = vcline = 0;
5a6c967e
CH
390 if (ex_vSCROLL == 0)
391 ex_vSCROLL = (value(WINDOW)+1)/2; /* round up so dft=6,11 */
59ae3464
MH
392}
393
394#ifdef CBREAK
395vintr()
396{
b3c5103a 397 extern jmp_buf readbuf;
47bdd628 398 extern int doingread;
59ae3464
MH
399
400 signal(SIGINT, vintr);
401 if (vcatch)
402 onintr();
403 ungetkey(ATTN);
404 draino();
47bdd628
SL
405 if (doingread) {
406 doingread = 0;
407 longjmp(readbuf, 1);
408 }
59ae3464
MH
409}
410#endif
411
412/*
413 * Set the size of the screen to size lines, to take effect the
414 * next time the screen is redrawn.
415 */
416vsetsiz(size)
417 int size;
418{
419 register int b;
420
421 if (bastate != VISUAL)
422 return;
423 b = LINES - 1 - size;
424 if (b >= LINES - 1)
425 b = LINES - 2;
426 if (b < 0)
427 b = 0;
428 basWTOP = b;
429 basWLINES = WBOT - b + 1;
430}
2de97448 431
5a6c967e 432#ifdef SIGWINCH
2de97448
JB
433winch()
434{
435 vsave();
5a6c967e 436 ignore(setty(normf));
2de97448
JB
437 longjmp(venv, 1);
438}
5a6c967e 439#endif