]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/nvi/cl/cl_funcs.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / nvi / cl / cl_funcs.c
1 /*-
2  * Copyright (c) 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1993, 1994, 1995, 1996
5  *      Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9
10 #include "config.h"
11
12 #ifndef lint
13 static const char sccsid[] = "$Id: cl_funcs.c,v 10.74 2012/10/11 10:30:16 zy Exp $";
14 #endif /* not lint */
15
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
19
20 #include <bitstring.h>
21 #include <ctype.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #ifdef HAVE_TERM_H
27 #include <term.h>
28 #endif
29 #include <termios.h>
30 #include <unistd.h>
31
32 #include "../common/common.h"
33 #include "../vi/vi.h"
34 #include "cl.h"
35
36 static void cl_rdiv __P((SCR *));
37
38 static int 
39 addstr4(SCR *sp, void *str, size_t len, int wide)
40 {
41         CL_PRIVATE *clp;
42         WINDOW *win;
43         size_t y, x;
44         int iv;
45
46         clp = CLP(sp);
47         win = CLSP(sp) ? CLSP(sp) : stdscr;
48
49         /*
50          * If ex isn't in control, it's the last line of the screen and
51          * it's a split screen, use inverse video.
52          */
53         iv = 0;
54         getyx(win, y, x);
55         if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
56             y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
57                 iv = 1;
58                 (void)wstandout(win);
59         }
60
61 #ifdef USE_WIDECHAR
62         if (wide) {
63             if (waddnwstr(win, str, len) == ERR)
64                 return (1);
65         } else 
66 #endif
67             if (waddnstr(win, str, len) == ERR)
68                     return (1);
69
70         if (iv)
71                 (void)wstandend(win);
72         return (0);
73 }
74
75 /*
76  * cl_waddstr --
77  *      Add len bytes from the string at the cursor, advancing the cursor.
78  *
79  * PUBLIC: int cl_waddstr __P((SCR *, const CHAR_T *, size_t));
80  */
81 int
82 cl_waddstr(SCR *sp, const CHAR_T *str, size_t len)
83 {
84     return addstr4(sp, (void *)str, len, 1);
85 }
86
87 /*
88  * cl_addstr --
89  *      Add len bytes from the string at the cursor, advancing the cursor.
90  *
91  * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t));
92  */
93 int
94 cl_addstr(SCR *sp, const char *str, size_t len)
95 {
96     return addstr4(sp, (void *)str, len, 0);
97 }
98
99 /*
100  * cl_attr --
101  *      Toggle a screen attribute on/off.
102  *
103  * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int));
104  */
105 int
106 cl_attr(SCR *sp, scr_attr_t attribute, int on)
107 {
108         CL_PRIVATE *clp;
109         WINDOW *win;
110
111         clp = CLP(sp);
112         win = CLSP(sp) ? CLSP(sp) : stdscr;
113
114         switch (attribute) {
115         case SA_ALTERNATE:
116         /*
117          * !!!
118          * There's a major layering violation here.  The problem is that the
119          * X11 xterm screen has what's known as an "alternate" screen.  Some
120          * xterm termcap/terminfo entries include sequences to switch to/from
121          * that alternate screen as part of the ti/te (smcup/rmcup) strings.
122          * Vi runs in the alternate screen, so that you are returned to the
123          * same screen contents on exit from vi that you had when you entered
124          * vi.  Further, when you run :shell, or :!date or similar ex commands,
125          * you also see the original screen contents.  This wasn't deliberate
126          * on vi's part, it's just that it historically sent terminal init/end
127          * sequences at those times, and the addition of the alternate screen
128          * sequences to the strings changed the behavior of vi.  The problem
129          * caused by this is that we don't want to switch back to the alternate
130          * screen while getting a new command from the user, when the user is
131          * continuing to enter ex commands, e.g.:
132          *
133          *      :!date                          <<< switch to original screen
134          *      [Hit return to continue]        <<< prompt user to continue
135          *      :command                        <<< get command from user
136          *
137          * Note that the :command input is a true vi input mode, e.g., input
138          * maps and abbreviations are being done.  So, we need to be able to
139          * switch back into the vi screen mode, without flashing the screen. 
140          *
141          * To make matters worse, the curses initscr() and endwin() calls will
142          * do this automatically -- so, this attribute isn't as controlled by
143          * the higher level screen as closely as one might like.
144          */
145         if (on) {
146                 if (clp->ti_te != TI_SENT) {
147                         clp->ti_te = TI_SENT;
148                         if (clp->smcup == NULL)
149                                 (void)cl_getcap(sp, "smcup", &clp->smcup);
150                         if (clp->smcup != NULL)
151                                 (void)tputs(clp->smcup, 1, cl_putchar);
152                 }
153         } else
154                 if (clp->ti_te != TE_SENT) {
155                         clp->ti_te = TE_SENT;
156                         if (clp->rmcup == NULL)
157                                 (void)cl_getcap(sp, "rmcup", &clp->rmcup);
158                         if (clp->rmcup != NULL)
159                                 (void)tputs(clp->rmcup, 1, cl_putchar);
160                         (void)fflush(stdout);
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
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
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
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
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
313 cl_deleteln(SCR *sp)
314 {
315         CL_PRIVATE *clp;
316         WINDOW *win;
317         size_t y, x;
318
319         clp = CLP(sp);
320         win = CLSP(sp) ? CLSP(sp) : stdscr;
321
322         /*
323          * This clause is required because the curses screen uses reverse
324          * video to delimit split screens.  If the screen does not do this,
325          * this code won't be necessary.
326          *
327          * If the bottom line was in reverse video, rewrite it in normal
328          * video before it's scrolled.
329          */
330         if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) {
331                 getyx(win, y, x);
332                 mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
333                 (void)wmove(win, y, x);
334         }
335
336         /*
337          * The bottom line is expected to be blank after this operation,
338          * and other screens must support that semantic.
339          */
340         return (wdeleteln(win) == ERR);
341 }
342
343 /* 
344  * cl_discard --
345  *      Discard a screen.
346  *
347  * PUBLIC: int cl_discard __P((SCR *, SCR **));
348  */
349 int
350 cl_discard(SCR *discardp, SCR **acquirep)
351 {
352         CL_PRIVATE *clp;
353         SCR*    tsp;
354
355         if (discardp) {
356             clp = CLP(discardp);
357             F_SET(clp, CL_LAYOUT);
358
359             if (CLSP(discardp)) {
360                     delwin(CLSP(discardp));
361                     discardp->cl_private = NULL;
362             }
363         }
364
365         /* no screens got a piece; we're done */
366         if (!acquirep) 
367                 return 0;
368
369         for (; (tsp = *acquirep) != NULL; ++acquirep) {
370                 clp = CLP(tsp);
371                 F_SET(clp, CL_LAYOUT);
372
373                 if (CLSP(tsp))
374                         delwin(CLSP(tsp));
375                 tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols,
376                                            tsp->roff, tsp->coff);
377         }
378
379         /* discardp is going away, acquirep is taking up its space. */
380         return (0);
381 }
382
383 /* 
384  * cl_ex_adjust --
385  *      Adjust the screen for ex.  This routine is purely for standalone
386  *      ex programs.  All special purpose, all special case.
387  *
388  * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t));
389  */
390 int
391 cl_ex_adjust(SCR *sp, exadj_t action)
392 {
393         CL_PRIVATE *clp;
394         int cnt;
395
396         clp = CLP(sp);
397         switch (action) {
398         case EX_TERM_SCROLL:
399                 /* Move the cursor up one line if that's possible. */
400                 if (clp->cuu1 != NULL)
401                         (void)tputs(clp->cuu1, 1, cl_putchar);
402                 else if (clp->cup != NULL)
403                         (void)tputs(tgoto(clp->cup,
404                             0, LINES - 2), 1, cl_putchar);
405                 else
406                         return (0);
407                 /* FALLTHROUGH */
408         case EX_TERM_CE:
409                 /* Clear the line. */
410                 if (clp->el != NULL) {
411                         (void)putchar('\r');
412                         (void)tputs(clp->el, 1, cl_putchar);
413                 } else {
414                         /*
415                          * Historically, ex didn't erase the line, so, if the
416                          * displayed line was only a single glyph, and <eof>
417                          * was more than one glyph, the output would not fully
418                          * overwrite the user's input.  To fix this, output
419                          * the maxiumum character number of spaces.  Note,
420                          * this won't help if the user entered extra prompt
421                          * or <blank> characters before the command character.
422                          * We'd have to do a lot of work to make that work, and
423                          * it's almost certainly not worth the effort.
424                          */
425                         for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
426                                 (void)putchar('\b');
427                         for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
428                                 (void)putchar(' ');
429                         (void)putchar('\r');
430                         (void)fflush(stdout);
431                 }
432                 break;
433         default:
434                 abort();
435         }
436         return (0);
437 }
438
439 /*
440  * cl_insertln --
441  *      Push down the current line, discarding the bottom line.
442  *
443  * PUBLIC: int cl_insertln __P((SCR *));
444  */
445 int
446 cl_insertln(SCR *sp)
447 {
448         WINDOW *win;
449         win = CLSP(sp) ? CLSP(sp) : stdscr;
450         /*
451          * The current line is expected to be blank after this operation,
452          * and the screen must support that semantic.
453          */
454         return (winsertln(win) == ERR);
455 }
456
457 /*
458  * cl_keyval --
459  *      Return the value for a special key.
460  *
461  * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
462  */
463 int
464 cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep)
465 {
466         CL_PRIVATE *clp;
467
468         /*
469          * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990,
470          * VWERASE is a 4BSD extension.
471          */
472         clp = CLP(sp);
473         switch (val) {
474         case KEY_VEOF:
475                 *dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE;
476                 break;
477         case KEY_VERASE:
478                 *dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE;
479                 break;
480         case KEY_VKILL:
481                 *dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE;
482                 break;
483 #ifdef VWERASE
484         case KEY_VWERASE:
485                 *dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE;
486                 break;
487 #endif
488         default:
489                 *dnep = 1;
490                 break;
491         }
492         return (0);
493 }
494
495 /*
496  * cl_move --
497  *      Move the cursor.
498  *
499  * PUBLIC: int cl_move __P((SCR *, size_t, size_t));
500  */
501 int
502 cl_move(SCR *sp, size_t lno, size_t cno)
503 {
504         WINDOW *win;
505         win = CLSP(sp) ? CLSP(sp) : stdscr;
506         /* See the comment in cl_cursor. */
507         if (wmove(win, RLNO(sp, lno), RCNO(sp, cno)) == ERR) {
508                 msgq(sp, M_ERR, "Error: move: l(%zu + %zu) c(%zu + %zu)",
509                     lno, sp->roff, cno, sp->coff);
510                 return (1);
511         }
512         return (0);
513 }
514
515 /*
516  * cl_refresh --
517  *      Refresh the screen.
518  *
519  * PUBLIC: int cl_refresh __P((SCR *, int));
520  */
521 int
522 cl_refresh(SCR *sp, int repaint)
523 {
524         GS *gp;
525         CL_PRIVATE *clp;
526         WINDOW *win;
527         SCR *psp, *tsp;
528         size_t y, x;
529
530         gp = sp->gp;
531         clp = CLP(sp);
532         win = CLSP(sp) ? CLSP(sp) : stdscr;
533
534         /*
535          * If we received a killer signal, we're done, there's no point
536          * in refreshing the screen.
537          */
538         if (clp->killersig)
539                 return (0);
540
541         /*
542          * If repaint is set, the editor is telling us that we don't know
543          * what's on the screen, so we have to repaint from scratch.
544          *
545          * If repaint set or the screen layout changed, we need to redraw
546          * any lines separating vertically split screens.  If the horizontal
547          * offsets are the same, then the split was vertical, and need to
548          * draw a dividing line.
549          */
550         if (repaint || F_ISSET(clp, CL_LAYOUT)) {
551                 getyx(stdscr, y, x);
552                 for (psp = sp; psp != NULL; psp = TAILQ_NEXT(psp, q))
553                         for (tsp = TAILQ_NEXT(psp, q); tsp != NULL;
554                             tsp = TAILQ_NEXT(tsp, q))
555                                 if (psp->roff == tsp->roff) {
556                                     if (psp->coff + psp->cols + 1 == tsp->coff)
557                                         cl_rdiv(psp);
558                                     else 
559                                     if (tsp->coff + tsp->cols + 1 == psp->coff)
560                                         cl_rdiv(tsp);
561                                 }
562                 (void)wmove(stdscr, y, x);
563                 F_CLR(clp, CL_LAYOUT);
564         }
565
566         /*
567          * In the curses library, doing wrefresh(curscr) is okay, but the
568          * screen flashes when we then apply the refresh() to bring it up
569          * to date.  So, use clearok().
570          */
571         if (repaint)
572                 clearok(curscr, 1);
573         /*
574          * Only do an actual refresh, when this is the focus window,
575          * i.e. the one holding the cursor. This assumes that refresh
576          * is called for that window after refreshing the others.
577          * This prevents the cursor being drawn in the other windows.
578          */
579         return (wnoutrefresh(stdscr) == ERR || 
580                 wnoutrefresh(win) == ERR || 
581                 (sp == clp->focus && doupdate() == ERR));
582 }
583
584 /*
585  * cl_rdiv --
586  *      Draw a dividing line between two vertically split screens.
587  */
588 static void
589 cl_rdiv(SCR *sp)
590 {
591 #ifdef __NetBSD__
592         mvvline(sp->roff, sp->cols + sp->coff, '|', sp->rows);
593 #else
594         mvvline(sp->roff, sp->cols + sp->coff, ACS_VLINE, sp->rows);
595 #endif
596 }
597
598 /*
599  * cl_rename --
600  *      Rename the file.
601  *
602  * PUBLIC: int cl_rename __P((SCR *, char *, int));
603  */
604 int
605 cl_rename(SCR *sp, char *name, int on)
606 {
607         GS *gp;
608         CL_PRIVATE *clp;
609         FILE *pfp;
610         char buf[256], *s, *e;
611         char * wid;
612         char cmd[64];
613
614         gp = sp->gp;
615         clp = CLP(sp);
616
617         /*
618          * XXX
619          * We can only rename windows for xterm.
620          */
621         if (on) {
622                 clp->focus = sp;
623                 if (!F_ISSET(clp, CL_RENAME_OK) ||
624                                 strncmp(OG_STR(gp, GO_TERM), "xterm", 5))
625                         return (0);
626
627                 if (clp->oname == NULL && (wid = getenv("WINDOWID"))) {
628                         snprintf(cmd, sizeof(cmd), "xprop -id %s WM_NAME", wid);
629                         if ((pfp = popen(cmd, "r")) == NULL)
630                                 goto rename;
631                         if (fgets(buf, sizeof(buf), pfp) == NULL) {
632                                 pclose(pfp);
633                                 goto rename;
634                         }
635                         pclose(pfp);
636                         if ((s = strchr(buf, '"')) != NULL &&
637                             (e = strrchr(buf, '"')) != NULL)
638                                 clp->oname = strndup(s + 1, e - s - 1);
639                 }
640
641 rename:         cl_setname(gp, name);
642
643                 F_SET(clp, CL_RENAME);
644         } else
645                 if (F_ISSET(clp, CL_RENAME)) {
646                         cl_setname(gp, clp->oname);
647
648                         F_CLR(clp, CL_RENAME);
649                 }
650         return (0);
651 }
652
653 /*
654  * cl_setname --
655  *      Set a X11 icon/window name.
656  *
657  * PUBLIC: void cl_setname __P((GS *, char *));
658  */
659 void
660 cl_setname(GS *gp, char *name)
661 {
662 /* X11 xterm escape sequence to rename the icon/window. */
663 #define XTERM_RENAME    "\033]0;%s\007"
664
665         (void)printf(XTERM_RENAME, name == NULL ? OG_STR(gp, GO_TERM) : name);
666         (void)fflush(stdout);
667 #undef XTERM_RENAME
668 }
669
670 /* 
671  * cl_split --
672  *      Split a screen.
673  *
674  * PUBLIC: int cl_split __P((SCR *, SCR *));
675  */
676 int
677 cl_split(SCR *origp, SCR *newp)
678 {
679         CL_PRIVATE *clp;
680
681         clp = CLP(origp);
682         F_SET(clp, CL_LAYOUT);
683
684         if (CLSP(origp))
685                 delwin(CLSP(origp));
686
687         origp->cl_private = subwin(stdscr, origp->rows, origp->cols,
688                                      origp->roff, origp->coff);
689         newp->cl_private = subwin(stdscr, newp->rows, newp->cols,
690                                      newp->roff, newp->coff);
691
692         /* origp is the original screen, giving up space to newp. */
693         return (0);
694 }
695
696 /*
697  * cl_suspend --
698  *      Suspend a screen.
699  *
700  * PUBLIC: int cl_suspend __P((SCR *, int *));
701  */
702 int
703 cl_suspend(SCR *sp, int *allowedp)
704 {
705         struct termios t;
706         CL_PRIVATE *clp;
707         WINDOW *win;
708         GS *gp;
709         size_t y, x;
710         int changed;
711
712         gp = sp->gp;
713         clp = CLP(sp);
714         win = CLSP(sp) ? CLSP(sp) : stdscr;
715         *allowedp = 1;
716
717         /*
718          * The ex implementation of this function isn't needed by screens not
719          * supporting ex commands that require full terminal canonical mode
720          * (e.g. :suspend).
721          *
722          * The vi implementation of this function isn't needed by screens not
723          * supporting vi process suspension, i.e. any screen that isn't backed
724          * by a UNIX shell.
725          *
726          * Setting allowedp to 0 will cause the editor to reject the command.
727          */
728         if (F_ISSET(sp, SC_EX)) { 
729                 /* Save the terminal settings, and restore the original ones. */
730                 if (F_ISSET(clp, CL_STDIN_TTY)) {
731                         (void)tcgetattr(STDIN_FILENO, &t);
732                         (void)tcsetattr(STDIN_FILENO,
733                             TCSASOFT | TCSADRAIN, &clp->orig);
734                 }
735
736                 /* Stop the process group. */
737                 (void)kill(0, SIGTSTP);
738
739                 /* Time passes ... */
740
741                 /* Restore terminal settings. */
742                 if (F_ISSET(clp, CL_STDIN_TTY))
743                         (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
744                 return (0);
745         }
746
747         /*
748          * Move to the lower left-hand corner of the screen.
749          *
750          * XXX
751          * Not sure this is necessary in System V implementations, but it
752          * shouldn't hurt.
753          */
754         getyx(win, y, x);
755         (void)wmove(win, LINES - 1, 0);
756         (void)wrefresh(win);
757
758         /*
759          * Temporarily end the screen.  System V introduced a semantic where
760          * endwin() could be restarted.  We use it because restarting curses
761          * from scratch often fails in System V.  4BSD curses didn't support
762          * restarting after endwin(), so we have to do what clean up we can
763          * without calling it.
764          */
765         /* Save the terminal settings. */
766         (void)tcgetattr(STDIN_FILENO, &t);
767
768         /* Restore the cursor keys to normal mode. */
769         (void)keypad(stdscr, FALSE);
770
771         /* Restore the window name. */
772         (void)cl_rename(sp, NULL, 0);
773
774         (void)endwin();
775
776         /*
777          * XXX
778          * Restore the original terminal settings.  This is bad -- the
779          * reset can cause character loss from the tty queue.  However,
780          * we can't call endwin() in BSD curses implementations, and too
781          * many System V curses implementations don't get it right.
782          */
783         (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig);
784
785         /* Stop the process group. */
786         (void)kill(0, SIGTSTP);
787
788         /* Time passes ... */
789
790         /*
791          * If we received a killer signal, we're done.  Leave everything
792          * unchanged.  In addition, the terminal has already been reset
793          * correctly, so leave it alone.
794          */
795         if (clp->killersig) {
796                 F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
797                 return (0);
798         }
799
800         /* Restore terminal settings. */
801         wrefresh(win);                      /* Needed on SunOs/Solaris ? */
802         if (F_ISSET(clp, CL_STDIN_TTY))
803                 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
804
805         /* Set the window name. */
806         (void)cl_rename(sp, sp->frp->name, 1);
807
808         /* Put the cursor keys into application mode. */
809         (void)keypad(stdscr, TRUE);
810
811         /* Refresh and repaint the screen. */
812         (void)wmove(win, y, x);
813         (void)cl_refresh(sp, 1);
814
815         /* If the screen changed size, set the SIGWINCH bit. */
816         if (cl_ssize(sp, 1, NULL, NULL, &changed))
817                 return (1);
818         if (changed)
819                 F_SET(CLP(sp), CL_SIGWINCH);
820
821         return (0);
822 }
823
824 /*
825  * cl_usage --
826  *      Print out the curses usage messages.
827  * 
828  * PUBLIC: void cl_usage __P((void));
829  */
830 void
831 cl_usage(void)
832 {
833 #define USAGE "\
834 usage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\
835 usage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n"
836         (void)fprintf(stderr, "%s", USAGE);
837 #undef  USAGE
838 }
839
840 #ifdef DEBUG
841 /*
842  * gdbrefresh --
843  *      Stub routine so can flush out curses screen changes using gdb.
844  */
845 static int
846         __attribute__((unused))
847 gdbrefresh(void)
848 {
849         refresh();
850         return (0);             /* XXX Convince gdb to run it. */
851 }
852 #endif