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.
7 * See the LICENSE file for redistribution information.
13 static const char sccsid[] = "$Id: cl_funcs.c,v 10.74 2012/10/11 10:30:16 zy Exp $";
16 #include <sys/types.h>
17 #include <sys/queue.h>
20 #include <bitstring.h>
32 #include "../common/common.h"
36 static void cl_rdiv __P((SCR *));
39 addstr4(SCR *sp, void *str, size_t len, int wide)
47 win = CLSP(sp) ? CLSP(sp) : stdscr;
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.
55 if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
56 y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
63 if (waddnwstr(win, str, len) == ERR)
67 if (waddnstr(win, str, len) == ERR)
77 * Add len bytes from the string at the cursor, advancing the cursor.
79 * PUBLIC: int cl_waddstr __P((SCR *, const CHAR_T *, size_t));
82 cl_waddstr(SCR *sp, const CHAR_T *str, size_t len)
84 return addstr4(sp, (void *)str, len, 1);
89 * Add len bytes from the string at the cursor, advancing the cursor.
91 * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t));
94 cl_addstr(SCR *sp, const char *str, size_t len)
96 return addstr4(sp, (void *)str, len, 0);
101 * Toggle a screen attribute on/off.
103 * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int));
106 cl_attr(SCR *sp, scr_attr_t attribute, int on)
112 win = CLSP(sp) ? CLSP(sp) : stdscr;
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.:
133 * :!date <<< switch to original screen
134 * [Hit return to continue] <<< prompt user to continue
135 * :command <<< get command from user
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.
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.
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);
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);
162 (void)fflush(stdout);
165 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
166 if (clp->smso == NULL)
169 (void)tputs(clp->smso, 1, cl_putchar);
171 (void)tputs(clp->rmso, 1, cl_putchar);
172 (void)fflush(stdout);
175 (void)wstandout(win);
177 (void)wstandend(win);
188 * Return the baud rate.
190 * PUBLIC: int cl_baud __P((SCR *, u_long *));
193 cl_baud(SCR *sp, u_long *ratep)
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.
206 switch (cfgetospeed(&clp->orig)) {
229 * Ring the bell/flash the screen.
231 * PUBLIC: int cl_bell __P((SCR *));
236 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE | SC_SCR_EX))
237 (void)write(STDOUT_FILENO, "\07", 1); /* \a */
240 * Vi has an edit option which determines if the terminal
241 * should be beeped or the screen flashed.
243 if (O_ISSET(sp, O_FLASH))
253 * Clear from the current cursor to the end of the line.
255 * PUBLIC: int cl_clrtoeol __P((SCR *));
265 win = CLSP(sp) ? CLSP(sp) : stdscr;
269 /* The cursor must be returned to its original position. */
271 for (spcnt = (sp->coff + sp->cols) - x; spcnt > 0; --spcnt)
272 (void)waddch(win, ' ');
273 (void)wmove(win, y, x);
277 return (wclrtoeol(win) == ERR);
282 * Return the current cursor position.
284 * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *));
287 cl_cursor(SCR *sp, size_t *yp, size_t *xp)
290 win = CLSP(sp) ? CLSP(sp) : stdscr;
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.
298 getyx(win, *yp, *xp);
308 * Delete the current line, scrolling all lines below it.
310 * PUBLIC: int cl_deleteln __P((SCR *));
320 win = CLSP(sp) ? CLSP(sp) : stdscr;
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.
327 * If the bottom line was in reverse video, rewrite it in normal
328 * video before it's scrolled.
330 if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) {
332 mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
333 (void)wmove(win, y, x);
337 * The bottom line is expected to be blank after this operation,
338 * and other screens must support that semantic.
340 return (wdeleteln(win) == ERR);
347 * PUBLIC: int cl_discard __P((SCR *, SCR **));
350 cl_discard(SCR *discardp, SCR **acquirep)
357 F_SET(clp, CL_LAYOUT);
359 if (CLSP(discardp)) {
360 delwin(CLSP(discardp));
361 discardp->cl_private = NULL;
365 /* no screens got a piece; we're done */
369 for (; (tsp = *acquirep) != NULL; ++acquirep) {
371 F_SET(clp, CL_LAYOUT);
375 tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols,
376 tsp->roff, tsp->coff);
379 /* discardp is going away, acquirep is taking up its space. */
385 * Adjust the screen for ex. This routine is purely for standalone
386 * ex programs. All special purpose, all special case.
388 * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t));
391 cl_ex_adjust(SCR *sp, exadj_t action)
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);
409 /* Clear the line. */
410 if (clp->el != NULL) {
412 (void)tputs(clp->el, 1, cl_putchar);
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.
425 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
427 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
430 (void)fflush(stdout);
441 * Push down the current line, discarding the bottom line.
443 * PUBLIC: int cl_insertln __P((SCR *));
449 win = CLSP(sp) ? CLSP(sp) : stdscr;
451 * The current line is expected to be blank after this operation,
452 * and the screen must support that semantic.
454 return (winsertln(win) == ERR);
459 * Return the value for a special key.
461 * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
464 cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep)
469 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990,
470 * VWERASE is a 4BSD extension.
475 *dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE;
478 *dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE;
481 *dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE;
485 *dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE;
499 * PUBLIC: int cl_move __P((SCR *, size_t, size_t));
502 cl_move(SCR *sp, size_t lno, size_t cno)
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);
517 * Refresh the screen.
519 * PUBLIC: int cl_refresh __P((SCR *, int));
522 cl_refresh(SCR *sp, int repaint)
532 win = CLSP(sp) ? CLSP(sp) : stdscr;
535 * If we received a killer signal, we're done, there's no point
536 * in refreshing the screen.
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.
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.
550 if (repaint || F_ISSET(clp, CL_LAYOUT)) {
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)
559 if (tsp->coff + tsp->cols + 1 == psp->coff)
562 (void)wmove(stdscr, y, x);
563 F_CLR(clp, CL_LAYOUT);
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().
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.
579 return (wnoutrefresh(stdscr) == ERR ||
580 wnoutrefresh(win) == ERR ||
581 (sp == clp->focus && doupdate() == ERR));
586 * Draw a dividing line between two vertically split screens.
592 mvvline(sp->roff, sp->cols + sp->coff, '|', sp->rows);
594 mvvline(sp->roff, sp->cols + sp->coff, ACS_VLINE, sp->rows);
602 * PUBLIC: int cl_rename __P((SCR *, char *, int));
605 cl_rename(SCR *sp, char *name, int on)
610 char buf[256], *s, *e;
619 * We can only rename windows for xterm.
623 if (!F_ISSET(clp, CL_RENAME_OK) ||
624 strncmp(OG_STR(gp, GO_TERM), "xterm", 5))
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)
631 if (fgets(buf, sizeof(buf), pfp) == NULL) {
636 if ((s = strchr(buf, '"')) != NULL &&
637 (e = strrchr(buf, '"')) != NULL)
638 clp->oname = strndup(s + 1, e - s - 1);
641 rename: cl_setname(gp, name);
643 F_SET(clp, CL_RENAME);
645 if (F_ISSET(clp, CL_RENAME)) {
646 cl_setname(gp, clp->oname);
648 F_CLR(clp, CL_RENAME);
655 * Set a X11 icon/window name.
657 * PUBLIC: void cl_setname __P((GS *, char *));
660 cl_setname(GS *gp, char *name)
662 /* X11 xterm escape sequence to rename the icon/window. */
663 #define XTERM_RENAME "\033]0;%s\007"
665 (void)printf(XTERM_RENAME, name == NULL ? OG_STR(gp, GO_TERM) : name);
666 (void)fflush(stdout);
674 * PUBLIC: int cl_split __P((SCR *, SCR *));
677 cl_split(SCR *origp, SCR *newp)
682 F_SET(clp, CL_LAYOUT);
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);
692 /* origp is the original screen, giving up space to newp. */
700 * PUBLIC: int cl_suspend __P((SCR *, int *));
703 cl_suspend(SCR *sp, int *allowedp)
714 win = CLSP(sp) ? CLSP(sp) : stdscr;
718 * The ex implementation of this function isn't needed by screens not
719 * supporting ex commands that require full terminal canonical mode
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
726 * Setting allowedp to 0 will cause the editor to reject the command.
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);
736 /* Stop the process group. */
737 (void)kill(0, SIGTSTP);
739 /* Time passes ... */
741 /* Restore terminal settings. */
742 if (F_ISSET(clp, CL_STDIN_TTY))
743 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
748 * Move to the lower left-hand corner of the screen.
751 * Not sure this is necessary in System V implementations, but it
755 (void)wmove(win, LINES - 1, 0);
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.
765 /* Save the terminal settings. */
766 (void)tcgetattr(STDIN_FILENO, &t);
768 /* Restore the cursor keys to normal mode. */
769 (void)keypad(stdscr, FALSE);
771 /* Restore the window name. */
772 (void)cl_rename(sp, NULL, 0);
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.
783 (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig);
785 /* Stop the process group. */
786 (void)kill(0, SIGTSTP);
788 /* Time passes ... */
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.
795 if (clp->killersig) {
796 F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
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);
805 /* Set the window name. */
806 (void)cl_rename(sp, sp->frp->name, 1);
808 /* Put the cursor keys into application mode. */
809 (void)keypad(stdscr, TRUE);
811 /* Refresh and repaint the screen. */
812 (void)wmove(win, y, x);
813 (void)cl_refresh(sp, 1);
815 /* If the screen changed size, set the SIGWINCH bit. */
816 if (cl_ssize(sp, 1, NULL, NULL, &changed))
819 F_SET(CLP(sp), CL_SIGWINCH);
826 * Print out the curses usage messages.
828 * PUBLIC: void cl_usage __P((void));
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);
843 * Stub routine so can flush out curses screen changes using gdb.
846 __attribute__((unused))
850 return (0); /* XXX Convince gdb to run it. */