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