1 /* $NetBSD: cl_funcs.c,v 1.9 2018/08/07 08:05:47 rin Exp $ */
2 /*-
3 * Copyright (c) 1993, 1994
4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 1993, 1994, 1995, 1996
6 * Keith Bostic. All rights reserved.
7 *
8 * See the LICENSE file for redistribution information.
9 */
10
11 #include "config.h"
12
13 #include <sys/cdefs.h>
14 #if 0
15 #ifndef lint
16 static const char sccsid[] = "Id: cl_funcs.c,v 10.72 2002/03/02 23:18:33 skimo Exp (Berkeley) Date: 2002/03/02 23:18:33 ";
17 #endif /* not lint */
18 #else
19 __RCSID("$NetBSD: cl_funcs.c,v 1.9 2018/08/07 08:05:47 rin Exp $");
20 #endif
21
22 #include <sys/types.h>
23 #include <sys/queue.h>
24 #include <sys/time.h>
25
26 #include <bitstring.h>
27 #include <ctype.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <termios.h>
33 #include <unistd.h>
34
35 #include "../common/common.h"
36 #include "../vi/vi.h"
37 #include "cl.h"
38
39 static void cl_rdiv __P((SCR *));
40
41 static int
addstr4(SCR * sp,const void * str,size_t len,int wide)42 addstr4(SCR *sp, const void *str, size_t len, int wide)
43 {
44 WINDOW *win;
45 size_t y, x;
46 int iv;
47
48 win = CLSP(sp) ? CLSP(sp) : stdscr;
49
50 /*
51 * If ex isn't in control, it's the last line of the screen and
52 * it's a split screen, use inverse video.
53 */
54 iv = 0;
55 getyx(win, y, x);
56 __USE(x);
57 if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
58 y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
59 iv = 1;
60 (void)wstandout(win);
61 }
62
63 #ifdef USE_WIDECHAR
64 if (wide) {
65 if (waddnwstr(win, str, len) == ERR)
66 return (1);
67 } else
68 #endif
69 if (waddnstr(win, str, len) == ERR)
70 return (1);
71
72 if (iv)
73 (void)wstandend(win);
74 return (0);
75 }
76
77 /*
78 * cl_waddstr --
79 * Add len bytes from the string at the cursor, advancing the cursor.
80 *
81 * PUBLIC: int cl_waddstr __P((SCR *, const CHAR_T *, size_t));
82 */
83 int
cl_waddstr(SCR * sp,const CHAR_T * str,size_t len)84 cl_waddstr(SCR *sp, const CHAR_T *str, size_t len)
85 {
86 return addstr4(sp, (const void *)str, len, 1);
87 }
88
89 /*
90 * cl_addstr --
91 * Add len bytes from the string at the cursor, advancing the cursor.
92 *
93 * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t));
94 */
95 int
cl_addstr(SCR * sp,const char * str,size_t len)96 cl_addstr(SCR *sp, const char *str, size_t len)
97 {
98 return addstr4(sp, (const void *)str, len, 0);
99 }
100
101 /*
102 * cl_attr --
103 * Toggle a screen attribute on/off.
104 *
105 * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int));
106 */
107 int
cl_attr(SCR * sp,scr_attr_t attribute,int on)108 cl_attr(SCR *sp, scr_attr_t attribute, int on)
109 {
110 CL_PRIVATE *clp;
111 WINDOW *win;
112
113 clp = CLP(sp);
114 win = CLSP(sp) ? CLSP(sp) : stdscr;
115
116 switch (attribute) {
117 case SA_ALTERNATE:
118 /*
119 * !!!
120 * There's a major layering violation here. The problem is that the
121 * X11 xterm screen has what's known as an "alternate" screen. Some
122 * xterm termcap/terminfo entries include sequences to switch to/from
123 * that alternate screen as part of the ti/te (smcup/rmcup) strings.
124 * Vi runs in the alternate screen, so that you are returned to the
125 * same screen contents on exit from vi that you had when you entered
126 * vi. Further, when you run :shell, or :!date or similar ex commands,
127 * you also see the original screen contents. This wasn't deliberate
128 * on vi's part, it's just that it historically sent terminal init/end
129 * sequences at those times, and the addition of the alternate screen
130 * sequences to the strings changed the behavior of vi. The problem
131 * caused by this is that we don't want to switch back to the alternate
132 * screen while getting a new command from the user, when the user is
133 * continuing to enter ex commands, e.g.:
134 *
135 * :!date <<< switch to original screen
136 * [Hit return to continue] <<< prompt user to continue
137 * :command <<< get command from user
138 *
139 * Note that the :command input is a true vi input mode, e.g., input
140 * maps and abbreviations are being done. So, we need to be able to
141 * switch back into the vi screen mode, without flashing the screen.
142 *
143 * To make matters worse, the curses initscr() and endwin() calls will
144 * do this automatically -- so, this attribute isn't as controlled by
145 * the higher level screen as closely as one might like.
146 */
147 if (on) {
148 if (clp->ti_te != TI_SENT) {
149 clp->ti_te = TI_SENT;
150 if (clp->smcup == NULL)
151 (void)cl_getcap(sp, "smcup", &clp->smcup);
152 if (clp->smcup != NULL)
153 (void)tputs(clp->smcup, 1, cl_putchar);
154 }
155 } else if (clp->ti_te != TE_SENT) {
156 clp->ti_te = TE_SENT;
157 if (clp->rmcup == NULL)
158 (void)cl_getcap(sp, "rmcup", &clp->rmcup);
159 if (clp->rmcup != NULL)
160 (void)tputs(clp->rmcup, 1, cl_putchar);
161 }
162 (void)fflush(stdout);
163 break;
164 case SA_INVERSE:
165 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
166 if (clp->smso == NULL)
167 return (1);
168 if (on)
169 (void)tputs(clp->smso, 1, cl_putchar);
170 else
171 (void)tputs(clp->rmso, 1, cl_putchar);
172 (void)fflush(stdout);
173 } else {
174 if (on)
175 (void)wstandout(win);
176 else
177 (void)wstandend(win);
178 }
179 break;
180 default:
181 abort();
182 }
183 return (0);
184 }
185
186 /*
187 * cl_baud --
188 * Return the baud rate.
189 *
190 * PUBLIC: int cl_baud __P((SCR *, u_long *));
191 */
192 int
cl_baud(SCR * sp,u_long * ratep)193 cl_baud(SCR *sp, u_long *ratep)
194 {
195 CL_PRIVATE *clp;
196
197 /*
198 * XXX
199 * There's no portable way to get a "baud rate" -- cfgetospeed(3)
200 * returns the value associated with some #define, which we may
201 * never have heard of, or which may be a purely local speed. Vi
202 * only cares if it's SLOW (w300), slow (w1200) or fast (w9600).
203 * Try and detect the slow ones, and default to fast.
204 */
205 clp = CLP(sp);
206 switch (cfgetospeed(&clp->orig)) {
207 case B50:
208 case B75:
209 case B110:
210 case B134:
211 case B150:
212 case B200:
213 case B300:
214 case B600:
215 *ratep = 600;
216 break;
217 case B1200:
218 *ratep = 1200;
219 break;
220 default:
221 *ratep = 9600;
222 break;
223 }
224 return (0);
225 }
226
227 /*
228 * cl_bell --
229 * Ring the bell/flash the screen.
230 *
231 * PUBLIC: int cl_bell __P((SCR *));
232 */
233 int
cl_bell(SCR * sp)234 cl_bell(SCR *sp)
235 {
236 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE | SC_SCR_EX))
237 (void)write(STDOUT_FILENO, "\07", 1); /* \a */
238 else {
239 /*
240 * Vi has an edit option which determines if the terminal
241 * should be beeped or the screen flashed.
242 */
243 if (O_ISSET(sp, O_FLASH))
244 (void)flash();
245 else
246 (void)beep();
247 }
248 return (0);
249 }
250
251 /*
252 * cl_clrtoeol --
253 * Clear from the current cursor to the end of the line.
254 *
255 * PUBLIC: int cl_clrtoeol __P((SCR *));
256 */
257 int
cl_clrtoeol(SCR * sp)258 cl_clrtoeol(SCR *sp)
259 {
260 WINDOW *win;
261 #if 0
262 size_t spcnt, y, x;
263 #endif
264
265 win = CLSP(sp) ? CLSP(sp) : stdscr;
266
267 #if 0
268 if (IS_VSPLIT(sp)) {
269 /* The cursor must be returned to its original position. */
270 getyx(win, y, x);
271 for (spcnt = (sp->coff + sp->cols) - x; spcnt > 0; --spcnt)
272 (void)waddch(win, ' ');
273 (void)wmove(win, y, x);
274 return (0);
275 } else
276 #endif
277 return (wclrtoeol(win) == ERR);
278 }
279
280 /*
281 * cl_cursor --
282 * Return the current cursor position.
283 *
284 * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *));
285 */
286 int
cl_cursor(SCR * sp,size_t * yp,size_t * xp)287 cl_cursor(SCR *sp, size_t *yp, size_t *xp)
288 {
289 WINDOW *win;
290 win = CLSP(sp) ? CLSP(sp) : stdscr;
291 /*
292 * The curses screen support splits a single underlying curses screen
293 * into multiple screens to support split screen semantics. For this
294 * reason the returned value must be adjusted to be relative to the
295 * current screen, and not absolute. Screens that implement the split
296 * using physically distinct screens won't need this hack.
297 */
298 getyx(win, *yp, *xp);
299 /*
300 *yp -= sp->roff;
301 *xp -= sp->coff;
302 */
303 return (0);
304 }
305
306 /*
307 * cl_deleteln --
308 * Delete the current line, scrolling all lines below it.
309 *
310 * PUBLIC: int cl_deleteln __P((SCR *));
311 */
312 int
cl_deleteln(SCR * sp)313 cl_deleteln(SCR *sp)
314 {
315 WINDOW *win;
316 size_t y, x;
317 #ifndef HAVE_MVWCHGAT
318 CHAR_T ch;
319 size_t col, lno, spcnt;
320 #endif
321
322 win = CLSP(sp) ? CLSP(sp) : stdscr;
323
324 /*
325 * This clause is required because the curses screen uses reverse
326 * video to delimit split screens. If the screen does not do this,
327 * this code won't be necessary.
328 *
329 * If the bottom line was in reverse video, rewrite it in normal
330 * video before it's scrolled.
331 *
332 * Check for the existence of a chgat function; XSI requires it, but
333 * historic implementations of System V curses don't. If it's not
334 * a #define, we'll fall back to doing it by hand, which is slow but
335 * acceptable.
336 *
337 * By hand means walking through the line, retrieving and rewriting
338 * each character. Curses has no EOL marker, so track strings of
339 * spaces, and copy the trailing spaces only if there's a non-space
340 * character following.
341 */
342 if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) {
343 getyx(win, y, x);
344 #ifdef HAVE_MVWCHGAT
345 mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
346 #else
347 for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) {
348 (void)wmove(win, lno, col);
349 ch = winch(win);
350 if (ISBLANK(ch))
351 ++spcnt;
352 else {
353 (void)wmove(win, lno, col - spcnt);
354 for (; spcnt > 0; --spcnt)
355 (void)waddch(win, ' ');
356 (void)waddch(win, ch);
357 }
358 if (++col >= sp->cols)
359 break;
360 }
361 #endif
362 (void)wmove(win, y, x);
363 }
364
365 /*
366 * The bottom line is expected to be blank after this operation,
367 * and other screens must support that semantic.
368 */
369 return (wdeleteln(win) == ERR);
370 }
371
372 /*
373 * cl_discard --
374 * Discard a screen.
375 *
376 * PUBLIC: int cl_discard __P((SCR *, SCR **));
377 */
378 int
cl_discard(SCR * discardp,SCR ** acquirep)379 cl_discard(SCR *discardp, SCR **acquirep)
380 {
381 CL_PRIVATE *clp;
382 SCR* tsp;
383
384 if (discardp) {
385 clp = CLP(discardp);
386 F_SET(clp, CL_LAYOUT);
387
388 if (CLSP(discardp)) {
389 delwin(CLSP(discardp));
390 discardp->cl_private = NULL;
391 }
392 }
393
394 /* no screens got a piece; we're done */
395 if (!acquirep)
396 return 0;
397
398 for (; (tsp = *acquirep) != NULL; ++acquirep) {
399 clp = CLP(tsp);
400 F_SET(clp, CL_LAYOUT);
401
402 if (CLSP(tsp))
403 delwin(CLSP(tsp));
404 tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols,
405 tsp->roff, tsp->coff);
406 }
407
408 /* discardp is going away, acquirep is taking up its space. */
409 return (0);
410 }
411
412 /*
413 * cl_ex_adjust --
414 * Adjust the screen for ex. This routine is purely for standalone
415 * ex programs. All special purpose, all special case.
416 *
417 * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t));
418 */
419 int
cl_ex_adjust(SCR * sp,exadj_t action)420 cl_ex_adjust(SCR *sp, exadj_t action)
421 {
422 CL_PRIVATE *clp;
423 int cnt;
424
425 clp = CLP(sp);
426 switch (action) {
427 case EX_TERM_SCROLL:
428 /* Move the cursor up one line if that's possible. */
429 if (clp->cuu1 != NULL)
430 (void)tputs(clp->cuu1, 1, cl_putchar);
431 else if (clp->cup != NULL)
432 (void)tputs(tgoto(clp->cup,
433 0, LINES - 2), 1, cl_putchar);
434 else
435 return (0);
436 /* FALLTHROUGH */
437 case EX_TERM_CE:
438 /* Clear the line. */
439 if (clp->el != NULL) {
440 (void)putchar('\r');
441 (void)tputs(clp->el, 1, cl_putchar);
442 } else {
443 /*
444 * Historically, ex didn't erase the line, so, if the
445 * displayed line was only a single glyph, and <eof>
446 * was more than one glyph, the output would not fully
447 * overwrite the user's input. To fix this, output
448 * the maxiumum character number of spaces. Note,
449 * this won't help if the user entered extra prompt
450 * or <blank> characters before the command character.
451 * We'd have to do a lot of work to make that work, and
452 * it's almost certainly not worth the effort.
453 */
454 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
455 (void)putchar('\b');
456 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
457 (void)putchar(' ');
458 (void)putchar('\r');
459 (void)fflush(stdout);
460 }
461 break;
462 default:
463 abort();
464 }
465 return (0);
466 }
467
468 #ifdef IMCTRL
469 /*
470 * cl_imctrl --
471 * Control the state of input method by using escape sequences compatible
472 * to Tera Term and RLogin.
473 *
474 * PUBLIC: void cl_imctrl __P((SCR *, imctrl_t));
475 */
476 void
cl_imctrl(SCR * sp,imctrl_t action)477 cl_imctrl(SCR *sp, imctrl_t action)
478 {
479 #define TT_IM_OFF "\033[<t" /* TTIMEST */
480 #define TT_IM_RESTORE "\033[<r" /* TTIMERS */
481 #define TT_IM_SAVE "\033[<s" /* TTIMESV */
482
483 if (!O_ISSET(sp, O_IMCTRL) && action != IMCTRL_INIT)
484 return;
485
486 switch (action) {
487 case IMCTRL_INIT:
488 (void)printf(TT_IM_OFF TT_IM_SAVE);
489 break;
490 case IMCTRL_OFF:
491 (void)printf(TT_IM_SAVE TT_IM_OFF);
492 break;
493 case IMCTRL_ON:
494 (void)printf(TT_IM_RESTORE);
495 break;
496 default:
497 abort();
498 }
499 (void)fflush(stdout);
500 }
501 #endif
502
503 /*
504 * cl_insertln --
505 * Push down the current line, discarding the bottom line.
506 *
507 * PUBLIC: int cl_insertln __P((SCR *));
508 */
509 int
cl_insertln(SCR * sp)510 cl_insertln(SCR *sp)
511 {
512 WINDOW *win;
513 win = CLSP(sp) ? CLSP(sp) : stdscr;
514 /*
515 * The current line is expected to be blank after this operation,
516 * and the screen must support that semantic.
517 */
518 return (winsertln(win) == ERR);
519 }
520
521 /*
522 * cl_keyval --
523 * Return the value for a special key.
524 *
525 * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
526 */
527 int
cl_keyval(SCR * sp,scr_keyval_t val,CHAR_T * chp,int * dnep)528 cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep)
529 {
530 CL_PRIVATE *clp;
531
532 /*
533 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990,
534 * VWERASE is a 4BSD extension.
535 */
536 clp = CLP(sp);
537 switch (val) {
538 case KEY_VEOF:
539 *dnep =
540 (*chp = clp->orig.c_cc[VEOF]) == (CHAR_T)_POSIX_VDISABLE;
541 break;
542 case KEY_VERASE:
543 *dnep =
544 (*chp = clp->orig.c_cc[VERASE]) == (CHAR_T)_POSIX_VDISABLE;
545 break;
546 case KEY_VKILL:
547 *dnep =
548 (*chp = clp->orig.c_cc[VKILL]) == (CHAR_T)_POSIX_VDISABLE;
549 break;
550 #ifdef VWERASE
551 case KEY_VWERASE:
552 *dnep =
553 (*chp = clp->orig.c_cc[VWERASE]) == (CHAR_T)_POSIX_VDISABLE;
554 break;
555 #endif
556 default:
557 *dnep = 1;
558 break;
559 }
560 return (0);
561 }
562
563 /*
564 * cl_move --
565 * Move the cursor.
566 *
567 * PUBLIC: int cl_move __P((SCR *, size_t, size_t));
568 */
569 int
cl_move(SCR * sp,size_t lno,size_t cno)570 cl_move(SCR *sp, size_t lno, size_t cno)
571 {
572 WINDOW *win;
573 win = CLSP(sp) ? CLSP(sp) : stdscr;
574 /* See the comment in cl_cursor. */
575 if (wmove(win, RLNO(sp, lno), RCNO(sp, cno)) == ERR) {
576 msgq(sp, M_ERR, "Error: move: l(%zu + %zu) c(%zu + %zu)",
577 lno, sp->roff, cno, sp->coff);
578 return (1);
579 }
580 return (0);
581 }
582
583 /*
584 * cl_refresh --
585 * Refresh the screen.
586 *
587 * PUBLIC: int cl_refresh __P((SCR *, int));
588 */
589 int
cl_refresh(SCR * sp,int repaint)590 cl_refresh(SCR *sp, int repaint)
591 {
592 CL_PRIVATE *clp;
593 WINDOW *win;
594 SCR *psp, *tsp;
595 size_t y, x;
596
597 clp = CLP(sp);
598 win = CLSP(sp) ? CLSP(sp) : stdscr;
599
600 /*
601 * If we received a killer signal, we're done, there's no point
602 * in refreshing the screen.
603 */
604 if (clp->killersig)
605 return (0);
606
607 /*
608 * If repaint is set, the editor is telling us that we don't know
609 * what's on the screen, so we have to repaint from scratch.
610 *
611 * If repaint set or the screen layout changed, we need to redraw
612 * any lines separating vertically split screens. If the horizontal
613 * offsets are the same, then the split was vertical, and need to
614 * draw a dividing line.
615 */
616 if (repaint || F_ISSET(clp, CL_LAYOUT)) {
617 getyx(stdscr, y, x);
618 for (psp = sp; psp != NULL; psp = TAILQ_NEXT(psp, q))
619 for (tsp = TAILQ_NEXT(psp, q); tsp != NULL;
620 tsp = TAILQ_NEXT(tsp, q))
621 if (psp->roff == tsp->roff) {
622 if (psp->coff + psp->cols + 1 == tsp->coff)
623 cl_rdiv(psp);
624 else
625 if (tsp->coff + tsp->cols + 1 == psp->coff)
626 cl_rdiv(tsp);
627 }
628 (void)wmove(stdscr, y, x);
629 F_CLR(clp, CL_LAYOUT);
630 }
631
632 /*
633 * In the curses library, doing wrefresh(curscr) is okay, but the
634 * screen flashes when we then apply the refresh() to bring it up
635 * to date. So, use clearok().
636 */
637 if (repaint)
638 clearok(curscr, 1);
639 /*
640 * Only do an actual refresh, when this is the focus window,
641 * i.e. the one holding the cursor. This assumes that refresh
642 * is called for that window after refreshing the others.
643 * This prevents the cursor being drawn in the other windows.
644 */
645 return (wnoutrefresh(stdscr) == ERR ||
646 wnoutrefresh(win) == ERR ||
647 (sp == clp->focus && doupdate() == ERR));
648 }
649
650 /*
651 * cl_rdiv --
652 * Draw a dividing line between two vertically split screens.
653 */
654 static void
cl_rdiv(SCR * sp)655 cl_rdiv(SCR *sp)
656 {
657 size_t cnt;
658
659 for (cnt = 0; cnt < sp->rows - 1; ++cnt) {
660 wmove(stdscr, sp->roff + cnt, sp->cols + sp->coff);
661 waddch(stdscr, '|');
662 }
663 }
664
665 /*
666 * cl_rename --
667 * Rename the file.
668 *
669 * PUBLIC: int cl_rename __P((SCR *, char *, int));
670 */
671 int
cl_rename(SCR * sp,char * name,int on)672 cl_rename(SCR *sp, char *name, int on)
673 {
674 CL_PRIVATE *clp;
675 FILE *pfp;
676 GS *gp;
677 char buf[256], *p;
678
679 gp = sp->gp;
680 clp = CLP(sp);
681
682 if (on) {
683 clp->focus = sp;
684 if (!F_ISSET(clp, CL_RENAME_OK))
685 return (0);
686
687 /*
688 * XXX
689 * We can only rename windows for xterm.
690 */
691 if (strncmp(OG_STR(gp, GO_TERM), "xterm", sizeof("xterm") - 1))
692 return (0);
693
694 /*
695 * XXX
696 * Try and figure out the current name of this window. There
697 * are two forms of the xwininfo output I've seen:
698 *
699 * Window id: 0x400000d "name"
700 * Window id: 0x140000d (name)
701 */
702 #define COMMAND \
703 "expr \"`xwininfo -id $WINDOWID | grep id:`\" : '.* [\"(]\\(.*\\)[\")]'"
704
705 if (clp->oname == NULL &&
706 (pfp = popen(COMMAND, "r")) != NULL) {
707 if (fgets(buf, sizeof(buf), pfp) != NULL &&
708 (p = strchr(buf, '\n')) != NULL) {
709 *p = '\0';
710 clp->oname = strdup(buf);
711 }
712 (void)fclose(pfp);
713 }
714
715 cl_setname(gp, name);
716
717 F_SET(clp, CL_RENAME);
718 } else
719 if (F_ISSET(clp, CL_RENAME)) {
720 cl_setname(gp, clp->oname);
721
722 F_CLR(clp, CL_RENAME);
723 }
724 return (0);
725 }
726
727 /*
728 * cl_setname --
729 * Set a X11 icon/window name.
730 *
731 * PUBLIC: void cl_setname __P((GS *, char *));
732 */
733 void
cl_setname(GS * gp,char * name)734 cl_setname(GS *gp, char *name)
735 {
736 /* X11 xterm escape sequence to rename the icon/window. */
737 #define XTERM_RENAME "\033]0;%s\007"
738
739 (void)printf(XTERM_RENAME, name == NULL ? OG_STR(gp, GO_TERM) : name);
740 (void)fflush(stdout);
741 }
742
743 /*
744 * cl_split --
745 * Split a screen.
746 *
747 * PUBLIC: int cl_split __P((SCR *, SCR *));
748 */
749 int
cl_split(SCR * origp,SCR * newp)750 cl_split(SCR *origp, SCR *newp)
751 {
752 CL_PRIVATE *clp;
753
754 clp = CLP(origp);
755 F_SET(clp, CL_LAYOUT);
756
757 if (CLSP(origp))
758 delwin(CLSP(origp));
759
760 origp->cl_private = subwin(stdscr, origp->rows, origp->cols,
761 origp->roff, origp->coff);
762 newp->cl_private = subwin(stdscr, newp->rows, newp->cols,
763 newp->roff, newp->coff);
764
765 /* origp is the original screen, giving up space to newp. */
766 return (0);
767 }
768
769 /*
770 * cl_suspend --
771 * Suspend a screen.
772 *
773 * PUBLIC: int cl_suspend __P((SCR *, int *));
774 */
775 int
cl_suspend(SCR * sp,int * allowedp)776 cl_suspend(SCR *sp, int *allowedp)
777 {
778 struct termios t;
779 CL_PRIVATE *clp;
780 WINDOW *win;
781 size_t y, x;
782 int changed;
783
784 clp = CLP(sp);
785 win = CLSP(sp) ? CLSP(sp) : stdscr;
786 *allowedp = 1;
787
788 /*
789 * The ex implementation of this function isn't needed by screens not
790 * supporting ex commands that require full terminal canonical mode
791 * (e.g. :suspend).
792 *
793 * The vi implementation of this function isn't needed by screens not
794 * supporting vi process suspension, i.e. any screen that isn't backed
795 * by a UNIX shell.
796 *
797 * Setting allowedp to 0 will cause the editor to reject the command.
798 */
799 if (F_ISSET(sp, SC_EX)) {
800 /* Save the terminal settings, and restore the original ones. */
801 if (F_ISSET(clp, CL_STDIN_TTY)) {
802 (void)tcgetattr(STDIN_FILENO, &t);
803 (void)tcsetattr(STDIN_FILENO,
804 TCSASOFT | TCSADRAIN, &clp->orig);
805 }
806
807 /* Stop the process group. */
808 (void)kill(0, SIGTSTP);
809
810 /* Time passes ... */
811
812 /* Restore terminal settings. */
813 if (F_ISSET(clp, CL_STDIN_TTY))
814 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
815 return (0);
816 }
817
818 /*
819 * Move to the lower left-hand corner of the screen.
820 *
821 * XXX
822 * Not sure this is necessary in System V implementations, but it
823 * shouldn't hurt.
824 */
825 getyx(win, y, x);
826 (void)wmove(win, LINES - 1, 0);
827 (void)wrefresh(win);
828
829 /*
830 * Temporarily end the screen. System V introduced a semantic where
831 * endwin() could be restarted. We use it because restarting curses
832 * from scratch often fails in System V. 4BSD curses didn't support
833 * restarting after endwin(), so we have to do what clean up we can
834 * without calling it.
835 */
836 /* Save the terminal settings. */
837 (void)tcgetattr(STDIN_FILENO, &t);
838
839 /* Restore the cursor keys to normal mode. */
840 (void)keypad(stdscr, FALSE);
841
842 /* Restore the window name. */
843 (void)cl_rename(sp, NULL, 0);
844
845 #ifdef HAVE_BSD_CURSES
846 (void)cl_attr(sp, SA_ALTERNATE, 0);
847 #else
848 (void)endwin();
849 #endif
850 /*
851 * XXX
852 * Restore the original terminal settings. This is bad -- the
853 * reset can cause character loss from the tty queue. However,
854 * we can't call endwin() in BSD curses implementations, and too
855 * many System V curses implementations don't get it right.
856 */
857 (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig);
858
859 /* Stop the process group. */
860 (void)kill(0, SIGTSTP);
861
862 /* Time passes ... */
863
864 /*
865 * If we received a killer signal, we're done. Leave everything
866 * unchanged. In addition, the terminal has already been reset
867 * correctly, so leave it alone.
868 */
869 if (clp->killersig) {
870 F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
871 return (0);
872 }
873
874 /* Restore terminal settings. */
875 wrefresh(win); /* Needed on SunOs/Solaris ? */
876 if (F_ISSET(clp, CL_STDIN_TTY))
877 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
878
879 #ifdef HAVE_BSD_CURSES
880 (void)cl_attr(sp, SA_ALTERNATE, 1);
881 #endif
882
883 /* Set the window name. */
884 (void)cl_rename(sp, sp->frp->name, 1);
885
886 /* Put the cursor keys into application mode. */
887 (void)keypad(stdscr, TRUE);
888
889 /* Refresh and repaint the screen. */
890 (void)wmove(win, y, x);
891 (void)cl_refresh(sp, 1);
892
893 /* If the screen changed size, set the SIGWINCH bit. */
894 if (cl_ssize(sp, 1, NULL, NULL, &changed))
895 return (1);
896 if (changed)
897 F_SET(CLP(sp), CL_SIGWINCH);
898
899 return (0);
900 }
901
902 /*
903 * cl_usage --
904 * Print out the curses usage messages.
905 *
906 * PUBLIC: void cl_usage __P((void));
907 */
908 void
cl_usage(void)909 cl_usage(void)
910 {
911 #define USAGE "\
912 usage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\
913 usage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n"
914 (void)fprintf(stderr, "%s", USAGE);
915 #undef USAGE
916 }
917
918 #ifdef DEBUG
919 /*
920 * gdbrefresh --
921 * Stub routine so can flush out curses screen changes using gdb.
922 */
923 int
gdbrefresh(void)924 gdbrefresh(void)
925 {
926 refresh();
927 return (0); /* XXX Convince gdb to run it. */
928 }
929 #endif
930