/* * cl_discard -- * Discard a screen. * * PUBLIC: int cl_discard __P((SCR *, SCR **)); */ int cl_discard(SCR *discardp, SCR **acquirep) { CL_PRIVATE *clp; SCR* tsp; if (discardp) { clp = CLP(discardp); F_SET(clp, CL_LAYOUT); if (CLSP(discardp)) { delwin(CLSP(discardp)); discardp->cl_private = NULL; } } /* no screens got a piece; we're done */ if (!acquirep) return 0; for (; (tsp = *acquirep) != NULL; ++acquirep) { clp = CLP(tsp); F_SET(clp, CL_LAYOUT); if (CLSP(tsp)) delwin(CLSP(tsp)); tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols, tsp->roff, tsp->coff); } /* discardp is going away, acquirep is taking up its space. */ return (0); }
/* * cl_refresh -- * Refresh the screen. * * PUBLIC: int cl_refresh __P((SCR *, int)); */ int cl_refresh(SCR *sp, int repaint) { CL_PRIVATE *clp; WINDOW *win; SCR *psp, *tsp; size_t y, x; clp = CLP(sp); win = CLSP(sp) ? CLSP(sp) : stdscr; /* * If we received a killer signal, we're done, there's no point * in refreshing the screen. */ if (clp->killersig) return (0); /* * If repaint is set, the editor is telling us that we don't know * what's on the screen, so we have to repaint from scratch. * * If repaint set or the screen layout changed, we need to redraw * any lines separating vertically split screens. If the horizontal * offsets are the same, then the split was vertical, and need to * draw a dividing line. */ if (repaint || F_ISSET(clp, CL_LAYOUT)) { getyx(stdscr, y, x); for (psp = sp; psp != NULL; psp = TAILQ_NEXT(psp, q)) for (tsp = TAILQ_NEXT(psp, q); tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) if (psp->roff == tsp->roff) { if (psp->coff + psp->cols + 1 == tsp->coff) cl_rdiv(psp); else if (tsp->coff + tsp->cols + 1 == psp->coff) cl_rdiv(tsp); } (void)wmove(stdscr, y, x); F_CLR(clp, CL_LAYOUT); } /* * In the curses library, doing wrefresh(curscr) is okay, but the * screen flashes when we then apply the refresh() to bring it up * to date. So, use clearok(). */ if (repaint) clearok(curscr, 1); /* * Only do an actual refresh, when this is the focus window, * i.e. the one holding the cursor. This assumes that refresh * is called for that window after refreshing the others. * This prevents the cursor being drawn in the other windows. */ return (wnoutrefresh(stdscr) == ERR || wnoutrefresh(win) == ERR || (sp == clp->focus && doupdate() == ERR)); }
/* * cl_keyval -- * Return the value for a special key. * * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *)); */ int cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep) { CL_PRIVATE *clp; /* * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990, * VWERASE is a 4BSD extension. */ clp = CLP(sp); switch (val) { case KEY_VEOF: *dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE; break; case KEY_VERASE: *dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE; break; case KEY_VKILL: *dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE; break; #ifdef VWERASE case KEY_VWERASE: *dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE; break; #endif default: *dnep = 1; break; } return (0); }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI MPI_Init(&argc, &argv); // define an Epetra communicator Epetra_MpiComm Comm(MPI_COMM_WORLD); #else Epetra_SerialComm Comm; #endif Trilinos_Util::CommandLineParser CLP(argc,argv); int nx = CLP.Get("-nx", 123); int ny = CLP.Get("-ny", 145); double tol = CLP.Get("-tol", 1e-12); string solver = CLP.Get("-solver","KLU"); cout << "nx = " << nx << endl; cout << "ny = " << ny << " (default value)" << endl; cout << "tol = " << tol << endl; cout << "solver = " << solver << endl; #ifdef HAVE_MPI MPI_Finalize(); #endif return(EXIT_SUCCESS); }
/* * cl_baud -- * Return the baud rate. * * PUBLIC: int cl_baud __P((SCR *, u_long *)); */ int cl_baud(SCR *sp, u_long *ratep) { CL_PRIVATE *clp; /* * XXX * There's no portable way to get a "baud rate" -- cfgetospeed(3) * returns the value associated with some #define, which we may * never have heard of, or which may be a purely local speed. Vi * only cares if it's SLOW (w300), slow (w1200) or fast (w9600). * Try and detect the slow ones, and default to fast. */ clp = CLP(sp); switch (cfgetospeed(&clp->orig)) { case B50: case B75: case B110: case B134: case B150: case B200: case B300: case B600: *ratep = 600; break; case B1200: *ratep = 1200; break; default: *ratep = 9600; break; } return (0); }
/* * cl_deleteln -- * Delete the current line, scrolling all lines below it. * * PUBLIC: int cl_deleteln __P((SCR *)); */ int cl_deleteln(SCR *sp) { CHAR_T ch; CL_PRIVATE *clp; WINDOW *win; size_t col, lno, spcnt, y, x; clp = CLP(sp); win = CLSP(sp) ? CLSP(sp) : stdscr; /* * This clause is required because the curses screen uses reverse * video to delimit split screens. If the screen does not do this, * this code won't be necessary. * * If the bottom line was in reverse video, rewrite it in normal * video before it's scrolled. * * Check for the existence of a chgat function; XSI requires it, but * historic implementations of System V curses don't. If it's not * a #define, we'll fall back to doing it by hand, which is slow but * acceptable. * * By hand means walking through the line, retrieving and rewriting * each character. Curses has no EOL marker, so track strings of * spaces, and copy the trailing spaces only if there's a non-space * character following. */ if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) { getyx(win, y, x); #ifdef mvchgat mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL); #else for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) { (void)wmove(win, lno, col); ch = winch(win); if (isblank(ch)) ++spcnt; else { (void)wmove(win, lno, col - spcnt); for (; spcnt > 0; --spcnt) (void)waddch(win, ' '); (void)waddch(win, ch); } if (++col >= sp->cols) break; } #endif (void)wmove(win, y, x); } /* * The bottom line is expected to be blank after this operation, * and other screens must support that semantic. */ return (wdeleteln(win) == ERR); }
/* * cl_rename -- * Rename the file. * * PUBLIC: int cl_rename __P((SCR *, char *, int)); */ int cl_rename(SCR *sp, char *name, int on) { CL_PRIVATE *clp; FILE *pfp; GS *gp; char buf[256], *p; gp = sp->gp; clp = CLP(sp); if (on) { clp->focus = sp; if (!F_ISSET(clp, CL_RENAME_OK)) return (0); /* * XXX * We can only rename windows for xterm. */ if (strncmp(OG_STR(gp, GO_TERM), "xterm", sizeof("xterm") - 1)) return (0); /* * XXX * Try and figure out the current name of this window. There * are two forms of the xwininfo output I've seen: * * Window id: 0x400000d "name" * Window id: 0x140000d (name) */ #define COMMAND \ "expr \"`xwininfo -id $WINDOWID | grep id:`\" : '.* [\"(]\\(.*\\)[\")]'" if (clp->oname == NULL && (pfp = popen(COMMAND, "r")) != NULL) { if (fgets(buf, sizeof(buf), pfp) != NULL && (p = strchr(buf, '\n')) != NULL) { *p = '\0'; clp->oname = strdup(buf); } (void)fclose(pfp); } cl_setname(gp, name); F_SET(clp, CL_RENAME); } else if (F_ISSET(clp, CL_RENAME)) { cl_setname(gp, clp->oname); F_CLR(clp, CL_RENAME); } return (0); }
/* * cl_ex_adjust -- * Adjust the screen for ex. This routine is purely for standalone * ex programs. All special purpose, all special case. * * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t)); */ int cl_ex_adjust(SCR *sp, exadj_t action) { CL_PRIVATE *clp; int cnt; clp = CLP(sp); switch (action) { case EX_TERM_SCROLL: /* Move the cursor up one line if that's possible. */ if (clp->cuu1 != NULL) (void)tputs(clp->cuu1, 1, cl_putchar); else if (clp->cup != NULL) (void)tputs(tgoto(clp->cup, 0, LINES - 2), 1, cl_putchar); else return (0); /* FALLTHROUGH */ case EX_TERM_CE: /* Clear the line. */ if (clp->el != NULL) { (void)putchar('\r'); (void)tputs(clp->el, 1, cl_putchar); } else { /* * Historically, ex didn't erase the line, so, if the * displayed line was only a single glyph, and <eof> * was more than one glyph, the output would not fully * overwrite the user's input. To fix this, output * the maxiumum character number of spaces. Note, * this won't help if the user entered extra prompt * or <blank> characters before the command character. * We'd have to do a lot of work to make that work, and * it's almost certainly not worth the effort. */ for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) (void)putchar('\b'); for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) (void)putchar(' '); (void)putchar('\r'); (void)fflush(stdout); } break; default: abort(); } return (0); }
/* * cl_split -- * Split a screen. * * PUBLIC: int cl_split __P((SCR *, SCR *)); */ int cl_split(SCR *origp, SCR *newp) { CL_PRIVATE *clp; clp = CLP(origp); F_SET(clp, CL_LAYOUT); if (CLSP(origp)) delwin(CLSP(origp)); origp->cl_private = subwin(stdscr, origp->rows, origp->cols, origp->roff, origp->coff); newp->cl_private = subwin(stdscr, newp->rows, newp->cols, newp->roff, newp->coff); /* origp is the original screen, giving up space to newp. */ return (0); }
static int addstr4(SCR *sp, void *str, size_t len, int wide) { CL_PRIVATE *clp; WINDOW *win; size_t y, x; int iv; clp = CLP(sp); win = CLSP(sp) ? CLSP(sp) : stdscr; /* * If ex isn't in control, it's the last line of the screen and * it's a split screen, use inverse video. */ iv = 0; getyx(win, y, x); if (!F_ISSET(sp, SC_SCR_EXWROTE) && y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) { iv = 1; (void)wstandout(win); } #ifdef USE_WIDECHAR if (wide) { if (waddnwstr(win, str, len) == ERR) return (1); } else #endif if (waddnstr(win, str, len) == ERR) return (1); if (iv) (void)wstandend(win); return (0); }
/* * cl_suspend -- * Suspend a screen. * * PUBLIC: int cl_suspend __P((SCR *, int *)); */ int cl_suspend(SCR *sp, int *allowedp) { struct termios t; CL_PRIVATE *clp; WINDOW *win; size_t y, x; int changed; clp = CLP(sp); win = CLSP(sp) ? CLSP(sp) : stdscr; *allowedp = 1; /* * The ex implementation of this function isn't needed by screens not * supporting ex commands that require full terminal canonical mode * (e.g. :suspend). * * The vi implementation of this function isn't needed by screens not * supporting vi process suspension, i.e. any screen that isn't backed * by a UNIX shell. * * Setting allowedp to 0 will cause the editor to reject the command. */ if (F_ISSET(sp, SC_EX)) { /* Save the terminal settings, and restore the original ones. */ if (F_ISSET(clp, CL_STDIN_TTY)) { (void)tcgetattr(STDIN_FILENO, &t); (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &clp->orig); } /* Stop the process group. */ (void)kill(0, SIGTSTP); /* Time passes ... */ /* Restore terminal settings. */ if (F_ISSET(clp, CL_STDIN_TTY)) (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); return (0); } /* * Move to the lower left-hand corner of the screen. * * XXX * Not sure this is necessary in System V implementations, but it * shouldn't hurt. */ getyx(win, y, x); (void)wmove(win, LINES - 1, 0); (void)wrefresh(win); /* * Temporarily end the screen. System V introduced a semantic where * endwin() could be restarted. We use it because restarting curses * from scratch often fails in System V. 4BSD curses didn't support * restarting after endwin(), so we have to do what clean up we can * without calling it. */ /* Save the terminal settings. */ (void)tcgetattr(STDIN_FILENO, &t); /* Restore the cursor keys to normal mode. */ (void)keypad(stdscr, FALSE); /* Restore the window name. */ (void)cl_rename(sp, NULL, 0); #ifdef HAVE_BSD_CURSES (void)cl_attr(sp, SA_ALTERNATE, 0); #else (void)endwin(); #endif /* * XXX * Restore the original terminal settings. This is bad -- the * reset can cause character loss from the tty queue. However, * we can't call endwin() in BSD curses implementations, and too * many System V curses implementations don't get it right. */ (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); /* Stop the process group. */ (void)kill(0, SIGTSTP); /* Time passes ... */ /* * If we received a killer signal, we're done. Leave everything * unchanged. In addition, the terminal has already been reset * correctly, so leave it alone. */ if (clp->killersig) { F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); return (0); } /* Restore terminal settings. */ wrefresh(win); /* Needed on SunOs/Solaris ? */ if (F_ISSET(clp, CL_STDIN_TTY)) (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); #ifdef HAVE_BSD_CURSES (void)cl_attr(sp, SA_ALTERNATE, 1); #endif /* Set the window name. */ (void)cl_rename(sp, sp->frp->name, 1); /* Put the cursor keys into application mode. */ (void)keypad(stdscr, TRUE); /* Refresh and repaint the screen. */ (void)wmove(win, y, x); (void)cl_refresh(sp, 1); /* If the screen changed size, set the SIGWINCH bit. */ if (cl_ssize(sp, 1, NULL, NULL, &changed)) return (1); if (changed) F_SET(CLP(sp), CL_SIGWINCH); return (0); }
/* * cl_attr -- * Toggle a screen attribute on/off. * * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int)); */ int cl_attr(SCR *sp, scr_attr_t attribute, int on) { CL_PRIVATE *clp; WINDOW *win; clp = CLP(sp); win = CLSP(sp) ? CLSP(sp) : stdscr; switch (attribute) { case SA_ALTERNATE: /* * !!! * There's a major layering violation here. The problem is that the * X11 xterm screen has what's known as an "alternate" screen. Some * xterm termcap/terminfo entries include sequences to switch to/from * that alternate screen as part of the ti/te (smcup/rmcup) strings. * Vi runs in the alternate screen, so that you are returned to the * same screen contents on exit from vi that you had when you entered * vi. Further, when you run :shell, or :!date or similar ex commands, * you also see the original screen contents. This wasn't deliberate * on vi's part, it's just that it historically sent terminal init/end * sequences at those times, and the addition of the alternate screen * sequences to the strings changed the behavior of vi. The problem * caused by this is that we don't want to switch back to the alternate * screen while getting a new command from the user, when the user is * continuing to enter ex commands, e.g.: * * :!date <<< switch to original screen * [Hit return to continue] <<< prompt user to continue * :command <<< get command from user * * Note that the :command input is a true vi input mode, e.g., input * maps and abbreviations are being done. So, we need to be able to * switch back into the vi screen mode, without flashing the screen. * * To make matters worse, the curses initscr() and endwin() calls will * do this automatically -- so, this attribute isn't as controlled by * the higher level screen as closely as one might like. */ if (on) { if (clp->ti_te != TI_SENT) { clp->ti_te = TI_SENT; if (clp->smcup == NULL) (void)cl_getcap(sp, "smcup", &clp->smcup); if (clp->smcup != NULL) (void)tputs(clp->smcup, 1, cl_putchar); } } else if (clp->ti_te != TE_SENT) { clp->ti_te = TE_SENT; if (clp->rmcup == NULL) (void)cl_getcap(sp, "rmcup", &clp->rmcup); if (clp->rmcup != NULL) (void)tputs(clp->rmcup, 1, cl_putchar); (void)fflush(stdout); } (void)fflush(stdout); break; case SA_INVERSE: if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) { if (clp->smso == NULL) return (1); if (on) (void)tputs(clp->smso, 1, cl_putchar); else (void)tputs(clp->rmso, 1, cl_putchar); (void)fflush(stdout); } else { if (on) (void)wstandout(win); else (void)wstandend(win); } break; default: abort(); } return (0); }
/* * cl_screen -- * Switch screen types. * * PUBLIC: int cl_screen __P((SCR *, u_int32_t)); */ int cl_screen(SCR *sp, u_int32_t flags) { CL_PRIVATE *clp; WINDOW *win; GS *gp; int ret, error; sigset_t oset; gp = sp->gp; clp = CLP(sp); win = CLSP(sp) ? CLSP(sp) : stdscr; ret = 0; /* * During initialization of the screen, block signals to make sure that * curses/terminfo routines are not interrupted. */ error = sigprocmask(SIG_BLOCK, &__sigblockset, &oset); /* See if the current information is incorrect. */ if (F_ISSET(gp, G_SRESTART)) { if (CLSP(sp)) { delwin(CLSP(sp)); sp->cl_private = NULL; } if (cl_quit(gp)) { ret = 1; goto end; } F_CLR(gp, G_SRESTART); } /* See if we're already in the right mode. */ if ((LF_ISSET(SC_EX) && F_ISSET(sp, SC_SCR_EX)) || (LF_ISSET(SC_VI) && F_ISSET(sp, SC_SCR_VI))) goto end; /* * Fake leaving ex mode. * * We don't actually exit ex or vi mode unless forced (e.g. by a window * size change). This is because many curses implementations can't be * called twice in a single program. Plus, it's faster. If the editor * "leaves" vi to enter ex, when it exits ex we'll just fall back into * vi. */ if (F_ISSET(sp, SC_SCR_EX)) F_CLR(sp, SC_SCR_EX); /* * Fake leaving vi mode. * * Clear out the rest of the screen if we're in the middle of a split * screen. Move to the last line in the current screen -- this makes * terminal scrolling happen naturally. Note: *don't* move past the * end of the screen, as there are ex commands (e.g., :read ! cat file) * that don't want to. Don't clear the info line, its contents may be * valid, e.g. :file|append. */ if (F_ISSET(sp, SC_SCR_VI)) { F_CLR(sp, SC_SCR_VI); if (TAILQ_NEXT(sp, q) != NULL) { (void)wmove(win, RLNO(sp, sp->rows), 0); wclrtobot(win); } (void)wmove(win, RLNO(sp, sp->rows) - 1, 0); wrefresh(win); } /* Enter the requested mode. */ if (LF_ISSET(SC_EX)) { if (cl_ex_init(sp)) { ret = 1; goto end; } F_SET(clp, CL_IN_EX | CL_SCR_EX_INIT); /* * If doing an ex screen for ex mode, move to the last line * on the screen. */ if (F_ISSET(sp, SC_EX) && clp->cup != NULL) tputs(tgoto(clp->cup, 0, O_VAL(sp, O_LINES) - 1), 1, cl_putchar); } else { if (cl_vi_init(sp)) { ret = 1; goto end; } F_CLR(clp, CL_IN_EX); F_SET(clp, CL_SCR_VI_INIT); } end: /* Unblock signals. */ if (error == 0) (void)sigprocmask(SIG_SETMASK, &oset, NULL); return ret; }
/* * cl_ex_init -- * Initialize the ex screen. */ static int cl_ex_init(SCR *sp) { CL_PRIVATE *clp; int error; const char *ttype; clp = CLP(sp); /* If already initialized, just set the terminal modes. */ if (F_ISSET(clp, CL_SCR_EX_INIT)) goto fast; /* If not reading from a file, we're done. */ if (!F_ISSET(clp, CL_STDIN_TTY)) return (0); if (F_ISSET(clp, CL_CHANGE_TERM)) { if (F_ISSET(clp, CL_SETUPTERM) && del_curterm(cur_term)) return (1); F_CLR(clp, CL_SETUPTERM | CL_CHANGE_TERM); } if (!F_ISSET(clp, CL_SETUPTERM)) { /* We'll need a terminal type. */ if (opts_empty(sp, O_TERM, 0)) return (1); ttype = O_STR(sp, O_TERM); (void)setupterm(ttype, STDOUT_FILENO, &error); if (error == 0 || error == -1) return (1); } /* Get the ex termcap/terminfo strings. */ (void)cl_getcap(sp, "cup", &clp->cup); (void)cl_getcap(sp, "smso", &clp->smso); (void)cl_getcap(sp, "rmso", &clp->rmso); (void)cl_getcap(sp, "el", &clp->el); (void)cl_getcap(sp, "cuu1", &clp->cuu1); /* Enter_standout_mode and exit_standout_mode are paired. */ if (clp->smso == NULL || clp->rmso == NULL) { if (clp->smso != NULL) { free(clp->smso); clp->smso = NULL; } if (clp->rmso != NULL) { free(clp->rmso); clp->rmso = NULL; } } /* * Turn on canonical mode, with normal input and output processing. * Start with the original terminal settings as the user probably * had them (including any local extensions) set correctly for the * current terminal. * * !!! * We can't get everything that we need portably; for example, ONLCR, * mapping <newline> to <carriage-return> on output isn't required * by POSIX 1003.1b-1993. If this turns out to be a problem, then * we'll either have to play some games on the mapping, or we'll have * to make all ex printf's output \r\n instead of \n. */ clp->ex_enter = clp->orig; clp->ex_enter.c_lflag |= ECHO | ECHOE | ECHOK | ICANON | IEXTEN | ISIG; #ifdef ECHOCTL clp->ex_enter.c_lflag |= ECHOCTL; #endif #ifdef ECHOKE clp->ex_enter.c_lflag |= ECHOKE; #endif clp->ex_enter.c_iflag |= ICRNL; clp->ex_enter.c_oflag |= OPOST; #ifdef ONLCR clp->ex_enter.c_oflag |= ONLCR; #endif fast: if (tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->ex_enter)) { if (errno == EINTR) goto fast; msgq(sp, M_SYSERR, "tcsetattr"); return (1); } return (0); }
/* * cl_vi_init -- * Initialize the curses vi screen. */ static int cl_vi_init(SCR *sp) { CL_PRIVATE *clp; char *o_cols, *o_lines, *o_term; const char *ttype; clp = CLP(sp); /* If already initialized, just set the terminal modes. */ if (F_ISSET(clp, CL_SCR_VI_INIT)) goto fast; /* Curses vi always reads from (and writes to) a terminal. */ if (!F_ISSET(clp, CL_STDIN_TTY) || !isatty(STDOUT_FILENO)) { msgq(sp, M_ERR, "016|Vi's standard input and output must be a terminal"); return (1); } /* We'll need a terminal type. */ if (opts_empty(sp, O_TERM, 0)) return (1); ttype = O_STR(sp, O_TERM); /* * XXX * Changing the row/column and terminal values is done by putting them * into the environment, which is then read by curses. What this loses * in ugliness, it makes up for in stupidity. We can't simply put the * values into the environment ourselves, because in the presence of a * kernel mechanism for returning the window size, entering values into * the environment will screw up future screen resizing events, e.g. if * the user enters a :shell command and then resizes their window. So, * if they weren't already in the environment, we make sure to delete * them immediately after setting them. * * XXX * Putting the TERM variable into the environment is necessary, even * though we're using newterm() here. We may be using initscr() as * the underlying function. */ o_term = getenv("TERM"); cl_putenv(sp, "TERM", ttype, 0); o_lines = getenv("LINES"); cl_putenv(sp, "LINES", NULL, (u_long)O_VAL(sp, O_LINES)); o_cols = getenv("COLUMNS"); cl_putenv(sp, "COLUMNS", NULL, (u_long)O_VAL(sp, O_COLUMNS)); /* Delete cur_term if exists. */ if (F_ISSET(clp, CL_SETUPTERM)) { if (del_curterm(cur_term)) return (1); F_CLR(clp, CL_SETUPTERM); } /* * XXX * The SunOS initscr() can't be called twice. Don't even think about * using it. It fails in subtle ways (e.g. select(2) on fileno(stdin) * stops working). (The SVID notes that applications should only call * initscr() once.) * * XXX * The HP/UX newterm doesn't support the NULL first argument, so we * have to specify the terminal type. */ errno = 0; if ((clp->screen = newterm(__UNCONST(ttype), stdout, stdin)) == NULL) { if (errno) msgq(sp, M_SYSERR, "%s", ttype); else msgq(sp, M_ERR, "%s: unknown terminal type", ttype); return (1); } if (o_term == NULL) cl_unsetenv(sp, "TERM"); if (o_lines == NULL) cl_unsetenv(sp, "LINES"); if (o_cols == NULL) cl_unsetenv(sp, "COLUMNS"); /* * XXX * Someone got let out alone without adult supervision -- the SunOS * newterm resets the signal handlers. There's a race, but it's not * worth closing. */ (void)sig_init(sp->gp, sp); /* * We use raw mode. What we want is 8-bit clean, however, signals * and flow control should continue to work. Admittedly, it sounds * like cbreak, but it isn't. Using cbreak() can get you additional * things like IEXTEN, which turns on flags like DISCARD and LNEXT. * * !!! * If raw isn't turning off echo and newlines, something's wrong. * However, it shouldn't hurt. */ noecho(); /* No character echo. */ nonl(); /* No CR/NL translation. */ raw(); /* 8-bit clean. */ idlok(stdscr, 1); /* Use hardware insert/delete line. */ /* Put the cursor keys into application mode. */ (void)keypad(stdscr, TRUE); /* * XXX * The screen TI sequence just got sent. See the comment in * cl_funcs.c:cl_attr(). */ clp->ti_te = TI_SENT; /* * XXX * Historic implementations of curses handled SIGTSTP signals * in one of three ways. They either: * * 1: Set their own handler, regardless. * 2: Did not set a handler if a handler was already installed. * 3: Set their own handler, but then called any previously set * handler after completing their own cleanup. * * We don't try and figure out which behavior is in place, we force * it to SIG_DFL after initializing the curses interface, which means * that curses isn't going to take the signal. Since curses isn't * reentrant (i.e., the whole curses SIGTSTP interface is a fantasy), * we're doing The Right Thing. */ (void)signal(SIGTSTP, SIG_DFL); /* * If flow control was on, turn it back on. Turn signals on. ISIG * turns on VINTR, VQUIT, VDSUSP and VSUSP. The main curses code * already installed a handler for VINTR. We're going to disable the * other three. * * XXX * We want to use ^Y as a vi scrolling command. If the user has the * DSUSP character set to ^Y (common practice) clean it up. As it's * equally possible that the user has VDSUSP set to 'a', we disable * it regardless. It doesn't make much sense to suspend vi at read, * so I don't think anyone will care. Alternatively, we could look * it up in the table of legal command characters and turn it off if * it matches one. VDSUSP wasn't in POSIX 1003.1-1990, so we test for * it. * * XXX * We don't check to see if the user had signals enabled originally. * If they didn't, it's unclear what we're supposed to do here, but * it's also pretty unlikely. */ if (tcgetattr(STDIN_FILENO, &clp->vi_enter)) { msgq(sp, M_SYSERR, "tcgetattr"); goto err; } if (clp->orig.c_iflag & IXON) clp->vi_enter.c_iflag |= IXON; if (clp->orig.c_iflag & IXOFF) clp->vi_enter.c_iflag |= IXOFF; clp->vi_enter.c_lflag |= ISIG; #ifdef VDSUSP clp->vi_enter.c_cc[VDSUSP] = _POSIX_VDISABLE; #endif clp->vi_enter.c_cc[VQUIT] = _POSIX_VDISABLE; clp->vi_enter.c_cc[VSUSP] = _POSIX_VDISABLE; /* * XXX * OSF/1 doesn't turn off the <discard>, <literal-next> or <status> * characters when curses switches into raw mode. It should be OK * to do it explicitly for everyone. */ #ifdef VDISCARD clp->vi_enter.c_cc[VDISCARD] = _POSIX_VDISABLE; #endif #ifdef VLNEXT clp->vi_enter.c_cc[VLNEXT] = _POSIX_VDISABLE; #endif #ifdef VSTATUS clp->vi_enter.c_cc[VSTATUS] = _POSIX_VDISABLE; #endif /* Initialize terminal based information. */ if (cl_term_init(sp)) goto err; fast: /* Set the terminal modes. */ if (tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &clp->vi_enter)) { msgq(sp, M_SYSERR, "tcsetattr"); err: (void)cl_vi_end(sp->gp); return (1); } return (0); }
/* * cl_read -- * Read characters from the input. */ static input_t cl_read(SCR *sp, u_int32_t flags, char *bp, size_t blen, int *nrp, struct timeval *tp) { struct termios term1, term2; CL_PRIVATE *clp; GS *gp; fd_set rdfd; input_t rval; int maxfd, nr, term_reset; gp = sp->gp; clp = CLP(sp); term_reset = 0; /* * 1: A read from a file or a pipe. In this case, the reads * never timeout regardless. This means that we can hang * when trying to complete a map, but we're going to hang * on the next read anyway. */ if (!F_ISSET(clp, CL_STDIN_TTY)) { switch (nr = read(STDIN_FILENO, bp, blen)) { case 0: return (INP_EOF); case -1: goto err; default: *nrp = nr; return (INP_OK); } /* NOTREACHED */ } /* * 2: A read with an associated timeout, e.g., trying to complete * a map sequence. If input exists, we fall into #3. */ if (tp != NULL) { FD_ZERO(&rdfd); FD_SET(STDIN_FILENO, &rdfd); switch (select(STDIN_FILENO + 1, &rdfd, NULL, NULL, tp)) { case 0: return (INP_TIMEOUT); case -1: goto err; default: break; } } /* * The user can enter a key in the editor to quote a character. If we * get here and the next key is supposed to be quoted, do what we can. * Reset the tty so that the user can enter a ^C, ^Q, ^S. There's an * obvious race here, when the key has already been entered, but there's * nothing that we can do to fix that problem. * * The editor can ask for the next literal character even thought it's * generally running in line-at-a-time mode. Do what we can. */ if (LF_ISSET(EC_QUOTED | EC_RAW) && !tcgetattr(STDIN_FILENO, &term1)) { term_reset = 1; if (LF_ISSET(EC_QUOTED)) { term2 = term1; term2.c_lflag &= ~ISIG; term2.c_iflag &= ~(IXON | IXOFF); (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &term2); } else (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &clp->vi_enter); } /* * 3: Wait for input. * * Select on the command input and scripting window file descriptors. * It's ugly that we wait on scripting file descriptors here, but it's * the only way to keep from locking out scripting windows. */ if (F_ISSET(gp, G_SCRWIN)) { loop: FD_ZERO(&rdfd); FD_SET(STDIN_FILENO, &rdfd); maxfd = STDIN_FILENO; if (F_ISSET(sp, SC_SCRIPT)) { FD_SET(sp->script->sh_master, &rdfd); if (sp->script->sh_master > maxfd) maxfd = sp->script->sh_master; } switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) { case 0: abort(); case -1: goto err; default: break; } if (!FD_ISSET(STDIN_FILENO, &rdfd)) { if (sscr_input(sp)) return (INP_ERR); goto loop; } } /* * 4: Read the input. * * !!! * What's going on here is some scary stuff. Ex runs the terminal in * canonical mode. So, the <newline> character terminating a line of * input is returned in the buffer, but a trailing <EOF> character is * not similarly included. As ex uses 0<EOF> and ^<EOF> as autoindent * commands, it has to see the trailing <EOF> characters to determine * the difference between the user entering "0ab" and "0<EOF>ab". We * leave an extra slot in the buffer, so that we can add a trailing * <EOF> character if the buffer isn't terminated by a <newline>. We * lose if the buffer is too small for the line and exactly N characters * are entered followed by an <EOF> character. */ #define ONE_FOR_EOF 1 switch (nr = read(STDIN_FILENO, bp, blen - ONE_FOR_EOF)) { case 0: /* EOF. */ /* * ^D in canonical mode returns a read of 0, i.e. EOF. EOF is * a valid command, but we don't want to loop forever because * the terminal driver is returning EOF because the user has * disconnected. The editor will almost certainly try to write * something before this fires, which should kill us, but You * Never Know. */ if (++clp->eof_count < 50) { bp[0] = clp->orig.c_cc[VEOF]; *nrp = 1; rval = INP_OK; } else rval = INP_EOF; break; case -1: /* Error or interrupt. */ err: if (errno == EINTR) rval = INP_INTR; else { rval = INP_ERR; msgq(sp, M_SYSERR, "input"); } break; default: /* Input characters. */ if (F_ISSET(sp, SC_EX) && bp[nr - 1] != '\n') bp[nr++] = clp->orig.c_cc[VEOF]; *nrp = nr; clp->eof_count = 0; rval = INP_OK; break; } /* Restore the terminal state if it was modified. */ if (term_reset) (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &term1); return (rval); }
/* * cl_event -- * Return a single event. * * PUBLIC: int cl_event __P((SCR *, EVENT *, u_int32_t, int)); */ int cl_event(SCR *sp, EVENT *evp, u_int32_t flags, int ms) { struct timeval t, *tp; CL_PRIVATE *clp; size_t lines, columns; int changed, nr = 0; CHAR_T *wp; size_t wlen; int rc; /* * Queue signal based events. We never clear SIGHUP or SIGTERM events, * so that we just keep returning them until the editor dies. */ clp = CLP(sp); retest: if (LF_ISSET(EC_INTERRUPT) || F_ISSET(clp, CL_SIGINT)) { if (F_ISSET(clp, CL_SIGINT)) { F_CLR(clp, CL_SIGINT); evp->e_event = E_INTERRUPT; } else evp->e_event = E_TIMEOUT; return (0); } if (F_ISSET(clp, CL_SIGHUP | CL_SIGTERM | CL_SIGWINCH)) { if (F_ISSET(clp, CL_SIGHUP)) { evp->e_event = E_SIGHUP; return (0); } if (F_ISSET(clp, CL_SIGTERM)) { evp->e_event = E_SIGTERM; return (0); } if (F_ISSET(clp, CL_SIGWINCH)) { F_CLR(clp, CL_SIGWINCH); if (cl_ssize(sp, 1, &lines, &columns, &changed)) return (1); if (changed) { (void)cl_resize(sp, lines, columns); evp->e_event = E_WRESIZE; return (0); } /* No real change, ignore the signal. */ } } /* Set timer. */ if (ms == 0) tp = NULL; else { t.tv_sec = ms / 1000; t.tv_usec = (ms % 1000) * 1000; tp = &t; } /* Read input characters. */ read: switch (cl_read(sp, LF_ISSET(EC_QUOTED | EC_RAW), clp->ibuf + clp->skip, SIZE(clp->ibuf) - clp->skip, &nr, tp)) { case INP_OK: rc = INPUT2INT5(sp, clp->cw, clp->ibuf, nr + clp->skip, wp, wlen); evp->e_csp = wp; evp->e_len = wlen; evp->e_event = E_STRING; if (rc < 0) { int n = -rc; memmove(clp->ibuf, clp->ibuf + nr + clp->skip - n, n); clp->skip = n; if (wlen == 0) goto read; } else if (rc == 0) clp->skip = 0; else msgq(sp, M_ERR, "323|Invalid input. Truncated."); break; case INP_EOF: evp->e_event = E_EOF; break; case INP_ERR: evp->e_event = E_ERR; break; case INP_INTR: goto retest; case INP_TIMEOUT: evp->e_event = E_TIMEOUT; break; default: abort(); } return (0); }
void *_festival_speak(void *nothing) { int ret; int bytes; int wave_cached; FT_Wave *fwave; int debug_count = 0; int r; int terminate = 0; char *callback; log_msg(OTTS_LOG_INFO, "festival: speaking thread starting.......\n"); cache_init(); set_speaking_thread_parameters(); while (1) { sem_wait: sem_wait(festival_semaphore); log_msg(OTTS_LOG_DEBUG, "Semaphore on, speaking\n"); opentts_audio_set_volume(module_audio_id, festival_volume); festival_stopped = 0; festival_speaking = 1; wave_cached = 0; fwave = NULL; terminate = 0; bytes = strlen(*festival_message); module_report_event_begin(); log_msg(OTTS_LOG_INFO, "Going to synthesize: |%s|", *festival_message); if (bytes > 0) { if (!is_text(festival_message_type)) { /* it is a raw text */ log_msg(OTTS_LOG_INFO, "Cache mechanisms..."); fwave = cache_lookup(*festival_message, festival_message_type, 1); if (fwave != NULL) { wave_cached = 1; if (fwave->num_samples != 0) { if (FestivalDebugSaveOutput) { char filename_debug [256]; sprintf(filename_debug, "/tmp/debug-festival-%d.snd", debug_count++); save_FT_Wave_snd(fwave, filename_debug); } festival_send_to_audio(fwave); if (!festival_stopped) { CLEAN_UP(0, module_report_event_end); } else { CLEAN_UP(0, module_report_event_stop); } } else { CLEAN_UP(0, module_report_event_end); } } } /* Set multi-mode for appropriate kind of events */ if (is_text(festival_message_type)) { /* it is a raw text */ ret = FestivalSetMultiMode(festival_info, "t"); if (ret != 0) CLP(0, module_report_event_stop); } else { /* it is some kind of event */ ret = FestivalSetMultiMode(festival_info, "nil"); if (ret != 0) CLP(0, module_report_event_stop); } switch (festival_message_type) { case SPD_MSGTYPE_TEXT: r = festivalStringToWaveRequest(festival_info, *festival_message); break; case SPD_MSGTYPE_SOUND_ICON: r = festivalSoundIcon(festival_info, *festival_message); break; case SPD_MSGTYPE_CHAR: r = festivalCharacter(festival_info, *festival_message); break; case SPD_MSGTYPE_KEY: r = festivalKey(festival_info, *festival_message); break; case SPD_MSGTYPE_SPELL: r = festivalSpell(festival_info, *festival_message); break; default: r = -1; } if (r < 0) { log_msg(OTTS_LOG_WARN, "Couldn't process the request to say the object."); CLP(0, module_report_event_stop); } } while (1) { wave_cached = 0; log_msg(OTTS_LOG_INFO, "Retrieving data\n"); /* (speechd-next) */ if (is_text(festival_message_type)) { if (festival_stopped) { log_msg(OTTS_LOG_INFO, "Module stopped 1"); CLEAN_UP(0, module_report_event_stop); } log_msg(OTTS_LOG_INFO, "Getting data in multi mode"); fwave = festivalGetDataMulti(festival_info, &callback, &festival_stop_request, FestivalReopenSocket); if (callback != NULL) { if ((festival_pause_requested) && (!strncmp (callback, INDEX_MARK_BODY, INDEX_MARK_BODY_LEN))) { log_msg(OTTS_LOG_NOTICE, "Pause requested, pausing."); module_report_index_mark (callback); g_free(callback); festival_pause_requested = 0; CLEAN_UP(0, module_report_event_pause); } else { module_report_index_mark (callback); g_free(callback); continue; } } } else { /* is event */ log_msg(OTTS_LOG_INFO, "Getting data in single mode"); fwave = festivalStringToWaveGetData(festival_info); terminate = 1; callback = NULL; } if (fwave == NULL) { log_msg(OTTS_LOG_INFO, "End of sound samples, terminating this message..."); CLEAN_UP(0, module_report_event_end); } if (festival_message_type == SPD_MSGTYPE_CHAR || festival_message_type == SPD_MSGTYPE_KEY || festival_message_type == SPD_MSGTYPE_SOUND_ICON) { log_msg(OTTS_LOG_DEBUG, "Storing record for %s in cache\n", *festival_message); /* cache_insert takes care of not inserting the same message again */ cache_insert(g_strdup(*festival_message), festival_message_type, fwave); wave_cached = 1; } if (festival_stopped) { log_msg(OTTS_LOG_NOTICE, "Module stopped 2"); CLEAN_UP(0, module_report_event_stop); } if (fwave->num_samples != 0) { log_msg(OTTS_LOG_INFO, "Sending message to audio: %ld bytes\n", (fwave->num_samples) * sizeof(short)); if (FestivalDebugSaveOutput) { char filename_debug[256]; sprintf(filename_debug, "/tmp/debug-festival-%d.snd", debug_count++); save_FT_Wave_snd(fwave, filename_debug); } log_msg(OTTS_LOG_INFO, "Playing sound samples"); festival_send_to_audio(fwave); if (!wave_cached) delete_FT_Wave(fwave); log_msg(OTTS_LOG_NOTICE, "End of playing sound samples"); } if (terminate) { log_msg(OTTS_LOG_INFO, "Ok, end of samples, returning"); CLP(0, module_report_event_end); } if (festival_stopped) { log_msg(OTTS_LOG_NOTICE, "Module stopped 3"); CLP(0, module_report_event_stop); } } } festival_stopped = 0; festival_speaking = 0; log_msg(OTTS_LOG_INFO, "festival: speaking thread ended.......\n"); pthread_exit(NULL); }