1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 /* Copyright (c) 1981 Regents of the University of California */
32
33 #pragma ident "%Z%%M% %I% %E% SMI"
34
35 #include "ex.h"
36 #include "ex_re.h"
37 #include "ex_tty.h"
38 #include "ex_vis.h"
39
40 /*
41 * Entry points to open and visual from command mode processor.
42 * The open/visual code breaks down roughly as follows:
43 *
44 * ex_v.c entry points, checking of terminal characteristics
45 *
46 * ex_vadj.c logical screen control, use of intelligent operations
47 * insert/delete line and coordination with screen image;
48 * updating of screen after changes.
49 *
50 * ex_vget.c input of single keys and reading of input lines
51 * from the echo area, handling of \ escapes on input for
52 * uppercase only terminals, handling of memory for repeated
53 * commands and small saved texts from inserts and partline
54 * deletes, notification of multi line changes in the echo
55 * area.
56 *
57 * ex_vmain.c main command decoding, some command processing.
58 *
59 * ex_voperate.c decoding of operator/operand sequences and
60 * contextual scans, implementation of word motions.
61 *
62 * ex_vops.c major operator interfaces, undos, motions, deletes,
63 * changes, opening new lines, shifts, replacements and yanks
64 * coordinating logical and physical changes.
65 *
66 * ex_vops2.c subroutines for operator interfaces in ex_vops.c,
67 * insert mode, read input line processing at lowest level.
68 *
69 * ex_vops3.c structured motion definitions of ( ) { } and [ ] operators,
70 * indent for lisp routines, () and {} balancing.
71 *
72 * ex_vput.c output routines, clearing, physical mapping of logical cursor
73 * positioning, cursor motions, handling of insert character
74 * and delete character functions of intelligent and unintelligent
75 * terminals, visual mode tracing routines (for debugging),
76 * control of screen image and its updating.
77 *
78 * ex_vwind.c window level control of display, forward and backward rolls,
79 * absolute motions, contextual displays, line depth determination
80 */
81
82 void setsize();
83 void winch();
84 void vintr();
85 void ovend(ttymode);
86
87 wchar_t atube[TUBESIZE];
88 jmp_buf venv;
89 int windowchg;
90 int sigok;
91
92 /* reinitialize window size after SIGWINCH */
windowinit()93 void windowinit()
94 {
95 windowchg = 0;
96 setsize();
97 if(value(vi_WINDOW) >= lines || options[vi_WINDOW].odefault == value(vi_WINDOW))
98 value(vi_WINDOW) = lines -1;
99 options[vi_WINDOW].odefault = lines - 1;
100 if(options[vi_SCROLL].odefault == value(vi_SCROLL))
101 value(vi_SCROLL) = value(vi_WINDOW)/2;
102 options[vi_SCROLL].odefault = (lines - 1)/2;
103 vsetsiz(value(vi_WINDOW));
104 setwind();
105 vok(atube, 1);
106 }
107
redraw()108 void redraw()
109 {
110 vsave();
111 windowinit();
112 vclear();
113 vdirty(0, lines);
114 if(state != VISUAL) {
115 vclean();
116 vmoveto(dot, cursor, 0);
117 } else {
118 vredraw(WTOP);
119 vrepaint(cursor);
120 vfixcurs();
121 }
122 }
123
124 /*ARGSUSED*/
125 void
126 #ifdef __STDC__
winch(int sig)127 winch(int sig)
128 #else
129 winch(sig)
130 int sig;
131 #endif
132 {
133 struct winsize jwin;
134 int l;
135
136 if(ioctl(0, TIOCGWINSZ, &jwin) != -1) {
137 #ifdef XPG4
138 oldlines = jwin.ws_row;
139 oldcolumns = jwin.ws_col;
140 #endif /* XPG4 */
141 if (sigok) {
142 if (columns != jwin.ws_col || lines != jwin.ws_row)
143 redraw();
144 }
145 }
146 else
147 windowchg++;
148 (void)signal(SIGWINCH, winch);
149 }
150
151 void
setsize()152 setsize()
153 {
154 struct winsize jwin;
155 int l;
156
157 if(ioctl(0, TIOCGWINSZ, &jwin) != -1) {
158 if (jwin.ws_col > 0)
159 columns = jwin.ws_col;
160 if (jwin.ws_row > 0)
161 lines = jwin.ws_row;
162 }
163
164 #ifdef XPG4
165 if (envlines != -1) {
166 lines = envlines;
167 }
168
169 if (envcolumns != -1) {
170 columns = envcolumns;
171 }
172
173 if (envlines != -1 || envcolumns != -1) {
174 jwin.ws_row = lines;
175 jwin.ws_col = columns;
176
177 if (ioctl(0, TIOCSWINSZ, &jwin) == -1) {
178 jwin.ws_row = oldlines;
179 jwin.ws_col = oldcolumns;
180
181 ioctl(0, TIOCSWINSZ, &jwin);
182 }
183 }
184 #endif /* XPG4 */
185
186 if (lines <= 1)
187 lines = 24;
188 l = lines;
189 if (columns <= 4)
190 columns = 1000;
191 value(vi_WINDOW) = options[vi_WINDOW].odefault = l - 1;
192 }
193
194 /*
195 * Enter open mode
196 */
197 void
oop(void)198 oop(void)
199 {
200 unsigned char *ic;
201 ttymode f; /* was register */
202 int resize;
203
204 windowchg = 0;
205 (void)signal(SIGWINCH, winch);
206 ovbeg();
207 if (peekchar() == '/') {
208 (void)vi_compile(getchar(), 1);
209 savere(&scanre);
210 if (execute(0, dot) == 0)
211 error(value(vi_TERSE) ? gettext("Fail") :
212 gettext("Pattern not found on addressed line"));
213 ic = (unsigned char *)loc1;
214 if (ic > linebuf && *ic == 0)
215 ic--;
216 } else {
217 getDOT();
218 ic = vskipwh(linebuf);
219 }
220 donewline();
221
222 /*
223 * If overstrike then have to HARDOPEN
224 * else if can move cursor up off current line can use CRTOPEN (~~vi1)
225 * otherwise have to use ONEOPEN (like adm3)
226 */
227 if (over_strike && !erase_overstrike)
228 bastate = HARDOPEN;
229 else if (cursor_address || cursor_up)
230 bastate = CRTOPEN;
231 else
232 bastate = ONEOPEN;
233 setwind();
234
235 /*
236 * To avoid bombing on glass-crt's when the line is too long
237 * pretend that such terminals are 160 columns wide.
238 * If a line is too wide for display, we will dynamically
239 * switch to hardcopy open mode.
240 */
241 if (state != CRTOPEN)
242 WCOLS = TUBECOLS;
243 if (!inglobal)
244 savevis();
245 vok(atube, 0);
246 if (state != CRTOPEN)
247 columns = WCOLS;
248 Outchar = vputchar;
249 f = ostart();
250 if (state == CRTOPEN) {
251 if (outcol == UKCOL)
252 outcol = 0;
253 vmoveitup(1, 1);
254 } else
255 outline = destline = WBOT;
256 vshow(dot, NOLINE);
257 vnline(ic);
258 vmain();
259 if (state != CRTOPEN)
260 vclean();
261 Command = (unsigned char *)"open";
262 ovend(f);
263 (void)signal(SIGWINCH, SIG_DFL);
264 }
265
266 void
ovbeg(void)267 ovbeg(void)
268 {
269
270 if (inopen)
271 error(gettext("Recursive open/visual not allowed"));
272 Vlines = lineDOL();
273 fixzero();
274 setdot();
275 pastwh();
276 dot = addr2;
277 }
278
279 void
ovend(ttymode f)280 ovend(ttymode f)
281 {
282
283 splitw++;
284 vgoto(WECHO, 0);
285 vclreol();
286 vgoto(WECHO, 0);
287 holdcm = 0;
288 splitw = 0;
289 ostop(f);
290 setoutt();
291 undvis();
292 columns = OCOLUMNS;
293 inopen = 0;
294 flusho();
295 netchHAD(Vlines);
296 }
297
298 /*
299 * Enter visual mode
300 */
301 void
vop(void)302 vop(void)
303 {
304 int c;
305 ttymode f; /* was register */
306 extern unsigned char termtype[];
307
308 if (!cursor_address && !cursor_up) {
309 if (initev) {
310 toopen:
311 if (generic_type)
312 merror(gettext("I don't know what kind of terminal you are on - all I have is '%s'."), termtype);
313 putNFL();
314 merror(gettext("[Using open mode]"));
315 putNFL();
316 oop();
317 return;
318 }
319 error(gettext("Visual needs addressable cursor or upline capability"));
320 }
321 if (over_strike && !erase_overstrike) {
322 if (initev)
323 goto toopen;
324 error(gettext("Can't use visual on a terminal which overstrikes"));
325 }
326 if (!clear_screen) {
327 if (initev)
328 goto toopen;
329 error(gettext("Visual requires clear screen capability"));
330 }
331 if (!scroll_forward) {
332 if (initev)
333 goto toopen;
334 error(gettext("Visual requires scrolling"));
335 }
336 windowchg = 0;
337 (void)signal(SIGWINCH, winch);
338 ovbeg();
339 bastate = VISUAL;
340 c = 0;
341 if (any(peekchar(), "+-^."))
342 c = getchar();
343 pastwh();
344 vsetsiz(isdigit(peekchar()) ? getnum() : value(vi_WINDOW));
345 setwind();
346 donewline();
347 vok(atube, 0);
348 if (!inglobal)
349 savevis();
350 Outchar = vputchar;
351 vmoving = 0;
352 f = ostart();
353 if (initev == 0) {
354 vcontext(dot, c);
355 vnline((unsigned char *)NOSTR);
356 }
357 vmain();
358 Command = (unsigned char *)"visual";
359 ovend(f);
360 (void)signal(SIGWINCH, SIG_DFL);
361 }
362
363 /*
364 * Hack to allow entry to visual with
365 * empty buffer since routines internally
366 * demand at least one line.
367 */
368 void
fixzero(void)369 fixzero(void)
370 {
371
372 if (dol == zero) {
373 bool ochng = chng;
374
375 vdoappend((unsigned char *)"");
376 if (!ochng)
377 sync();
378 addr1 = addr2 = one;
379 } else if (addr2 == zero)
380 addr2 = one;
381 }
382
383 /*
384 * Save lines before visual between unddol and truedol.
385 * Accomplish this by throwing away current [unddol,truedol]
386 * and then saving all the lines in the buffer and moving
387 * unddol back to dol. Don't do this if in a global.
388 *
389 * If you do
390 * g/xxx/vi.
391 * and then do a
392 * :e xxxx
393 * at some point, and then quit from the visual and undo
394 * you get the old file back. Somewhat weird.
395 */
396 void
savevis(void)397 savevis(void)
398 {
399
400 if (inglobal)
401 return;
402 truedol = unddol;
403 saveall();
404 unddol = dol;
405 undkind = UNDNONE;
406 }
407
408 /*
409 * Restore a sensible state after a visual/open, moving the saved
410 * stuff back to [unddol,dol], and killing the partial line kill indicators.
411 */
412 void
undvis(void)413 undvis(void)
414 {
415
416 if (ruptible)
417 signal(SIGINT, onintr);
418 squish();
419 pkill[0] = pkill[1] = 0;
420 unddol = truedol;
421 unddel = zero;
422 undap1 = one;
423 undap2 = dol + 1;
424 undkind = UNDALL;
425 if (undadot <= zero || undadot > dol)
426 undadot = zero+1;
427 }
428
429 /*
430 * Set the window parameters based on the base state bastate
431 * and the available buffer space.
432 */
433 void
setwind(void)434 setwind(void)
435 {
436
437 WCOLS = columns;
438 switch (bastate) {
439
440 case ONEOPEN:
441 if (auto_right_margin)
442 WCOLS--;
443 /* fall into ... */
444
445 case HARDOPEN:
446 basWTOP = WTOP = WBOT = WECHO = 0;
447 ZERO = 0;
448 holdcm++;
449 break;
450
451 case CRTOPEN:
452 basWTOP = lines - 2;
453 /* fall into */
454
455 case VISUAL:
456 ZERO = lines - TUBESIZE / WCOLS;
457 if (ZERO < 0)
458 ZERO = 0;
459 if (ZERO > basWTOP)
460 error(gettext("Screen too large for internal buffer"));
461 WTOP = basWTOP; WBOT = lines - 2; WECHO = lines - 1;
462 break;
463 }
464 state = bastate;
465 basWLINES = WLINES = WBOT - WTOP + 1;
466 }
467
468 /*
469 * Can we hack an open/visual on this terminal?
470 * If so, then divide the screen buffer up into lines,
471 * and initialize a bunch of state variables before we start.
472 */
473 static unsigned char vlinebuf[LBSIZE];
474
475 void
vok(wchar_t * atube,int undo)476 vok(wchar_t *atube, int undo)
477 {
478 int i;
479 static int beenhere;
480
481 if (WCOLS == 1000)
482 serror((unsigned char *)
483 gettext("Don't know enough about your terminal to use %s"),
484 Command);
485 if (WCOLS > TUBECOLS)
486 error(gettext("Terminal too wide"));
487 if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE)
488 error(gettext("Screen too large"));
489
490 vtube0 = atube;
491 if(beenhere)
492 vclrbyte(atube, WCOLS * (WECHO - ZERO + 1));
493 for (i = 0; i < ZERO; i++)
494 vtube[i] = (wchar_t *) 0;
495 for (; i <= WECHO; i++)
496 vtube[i] = atube, atube += WCOLS;
497 if(beenhere++) {
498 for (; i < TUBELINES; i++)
499 vtube[i] = (wchar_t *) 0;
500 }
501 vutmp = vlinebuf;
502 if(!undo) {
503 vundkind = VNONE;
504 vUNDdot = 0;
505 }
506 OCOLUMNS = columns;
507 inopen = 1;
508 #ifdef CBREAK
509 signal(SIGINT, vintr);
510 #endif
511 vmoving = 0;
512 splitw = 0;
513 doomed = 0;
514 holdupd = 0;
515 if(!undo)
516 Peekkey = 0;
517 vcnt = vcline = 0;
518 if (vSCROLL == 0)
519 vSCROLL = value(vi_SCROLL);
520 }
521
522 #ifdef CBREAK
523 /*ARGSUSED*/
524 void
525 #ifdef __STDC__
vintr(int sig)526 vintr(int sig)
527 #else
528 vintr(sig)
529 int sig;
530 #endif
531 {
532
533 signal(SIGINT, vintr);
534 if (vcatch)
535 onintr(0);
536 ungetkey(ATTN);
537 draino();
538 }
539 #endif
540
541 /*
542 * Set the size of the screen to size lines, to take effect the
543 * next time the screen is redrawn.
544 */
545 void
vsetsiz(int size)546 vsetsiz(int size)
547 {
548 int b;
549
550 if (bastate != VISUAL)
551 return;
552 b = lines - 1 - size;
553 if (b >= lines - 1)
554 b = lines - 2;
555 if (b < 0)
556 b = 0;
557 basWTOP = b;
558 basWLINES = WBOT - b + 1;
559 }
560