int restartterm(char *tm, int fd, int *err_return) { size_t len; int err_code; const char *err_msg, *terminfo; char *old_names, *old_strings, *old_term, *filename; static const char def_termname[] = M_TERM_NAME; static const char def_terminfo[] = M_TERMINFO_DIR; err_code = 1; filename = NULL; old_term = cur_term->_term; old_names = cur_term->_names; old_strings = cur_term->_str_table; terminfo = getenv("TERMINFO"); if (terminfo == NULL || terminfo[0] == '\0') { terminfo = def_terminfo; } else { terminfo = (const char *) strdup((char *) terminfo); if (terminfo == NULL) { /* Not really true... */ err_msg = e_terminal; err_code = 2; goto error; } } if ((tm == NULL) && (((tm = getenv("TERM")) == NULL) || (*tm == '\0'))) { tm = (char *)def_termname; } /* Remember the terminal name being loaded. */ cur_term->_term = strdup(tm); if (cur_term->_term == NULL) { err_msg = e_terminal; err_code = 2; goto error; } /* Length of path we're going to construct. */ len = strlen(terminfo) + 3 + strlen(tm); if ((len > PATH_MAX) || ((filename = (char *)malloc(PATH_MAX + 1)) == NULL)) { err_msg = e_pathmax; err_code = 2; goto error; } /* Construct terminfo filename. */ (void) sprintf(filename, "%s/%c/%s", terminfo, tm[0], tm); /* Go looking for compiled terminal definition. */ if (__m_read_terminfo(filename, cur_term) < 0) { /* Length of default terminfo path. */ len = strlen(def_terminfo) + 3 + strlen(tm); if (len > PATH_MAX) { err_msg = e_pathmax; err_code = 2; goto error; } (void) sprintf(filename, "%s/%c/%s", def_terminfo, tm[0], tm); if (__m_read_terminfo(filename, cur_term) < 0) { err_msg = e_unknown; err_code = 0; goto error; } } if (use_environment) { char *env; #ifdef TIOCGWINSZ /* * Use ioctl(TIOCGWINSZ) to get row and column values. These * values may override the default terminfo settings. */ { struct winsize wininfo; if (ioctl(fd, TIOCGWINSZ, &wininfo) != -1) { if (0 < wininfo.ws_col) columns = wininfo.ws_col; if (0 < wininfo.ws_row) lines = wininfo.ws_row; } } #endif /* TIOCGWINSZ */ /* Check to see is the user wants a particular size terminal. */ if ((env = getenv("LINES")) != NULL) { int nlines = (int) strtol(env, (char **) 0, 10); if (0 < nlines) lines = nlines; } if ((env = getenv("COLUMNS")) != NULL) { int ncolumns = (int) strtol(env, (char **) 0, 10); if (0 < ncolumns) columns = ncolumns; } } if (command_character != NULL && getenv("CC") != NULL) do_prototype(); /* * If no_color_video is disabled, then assign it a value that * permits all attributes in combination with colour. */ if (no_color_video == -1) no_color_video = 0; __m_mvcur_cost(); error: if (filename != NULL) free(filename); if (terminfo != def_terminfo) free((void *) terminfo); if (err_return != NULL) { *err_return = err_code; if (err_code == 1) { err_code = OK; } else { err_code = ERR; cur_term->_term = old_term; cur_term->_names = old_names; cur_term->_str_table = old_strings; } } else if (err_code != 1) { (void) fprintf(stderr, err_msg, tm); exit(1); } if (err_code == OK) { if (old_names != NULL) free(old_names); if (old_strings != NULL) free(old_strings); if (old_term != NULL) free(old_term); } return (err_code); }
/* * Create a new terminal screen. Used if a program is going to be sending * output to more than one terminal. It returns a SCREEN* for the terminal. * The parameters are a terminal name, output FILE*, and input FILE*. If * the terminal name is null then $TERM is used. The program must also * call endwin() for each terminal being used before exiting from curses. * If newterm() is called more than once for the same terminal, the first * terminal referred to must be the last one for which endwin() is called. */ SCREEN * newterm(char *term, FILE *out_fp, FILE *in_fp) { WINDOW *w; t_wide_io *wio; SCREEN *sp, *osp; int i, n, y, errret; /* * Input stream should be unbuffered so that m_tfgetc() works * correctly on BSD and SUN systems. */ (void) setvbuf(in_fp, (char *) 0, _IONBF, BUFSIZ); #if 0 /* * Not sure whether we really want to concern ourselves with the output * buffer scheme. Might be best to leave it upto the application to * deal with buffer schemes and when to perform flushes. * * MKS Vi uses MKS Curses and so must support the ability to switch in * and out of Curses mode when switching from Vi to Ex and back. * Problem is that in Vi mode you would prefer full buffered output to * give updates a smoother appearance and Ex mode you require line * buffered in order to see prompts and messages. */ (void) setvbuf(out_fp, (char *) 0, _IOLBF, BUFSIZ); #endif errno = 0; if (__m_setupterm(term, fileno(in_fp), fileno(out_fp), &errret) == ERR) { switch (errret) { case -1: errno = ENOMEM; break; case 2: errno = ENAMETOOLONG; break; case 0: default: errno = ENOENT; break; } goto error1; } if (__m_doupdate_init()) goto error1; if ((sp = (SCREEN *) calloc(1, sizeof (*sp))) == NULL) goto error1; sp->_kfd = -1; sp->_if = in_fp; sp->_of = out_fp; sp->_term = cur_term; sp->_unget._size = __m_decode_init((t_decode **) &sp->_decode); /* * Maximum length of a multbyte key sequence, including * multibyte characters and terminal function keys. */ if (sp->_unget._size < (M_TYPEAHEAD_SIZE + MB_LEN_MAX)) sp->_unget._size = M_TYPEAHEAD_SIZE + MB_LEN_MAX; sp->_unget._stack = calloc((size_t) sp->_unget._size, sizeof (*sp->_unget._stack)); if (sp->_unget._stack == NULL) goto error2; if ((wio = (t_wide_io *) calloc(1, sizeof (*wio))) == NULL) goto error2; /* Setup wide input for XCurses. */ wio->get = (int (*)(void *)) wgetch; wio->unget = __xc_ungetc; wio->reset = __xc_clearerr; wio->iserror = __xc_ferror; wio->iseof = __xc_feof; sp->_in = wio; if (assume_one_line) { /* Assume only one line. */ lines = 1; /* Disable capabilities that assume more than one line. */ clear_screen = clr_eos = cursor_up = cursor_down = NULL; cursor_home = cursor_to_ll = cursor_address = NULL; row_address = parm_up_cursor = parm_down_cursor = NULL; /* Re-evaluate the cursor motion costs. */ __m_mvcur_cost(); /* Reset flag for subsequent calls to newterm(). */ assume_one_line = FALSE; } if ((sp->_curscr = newwin(lines, columns, 0, 0)) == NULL) goto error2; if ((sp->_newscr = newwin(lines, columns, 0, 0)) == NULL) goto error2; #if defined(_LP64) sp->_hash = (unsigned int *) calloc(lines, sizeof (*sp->_hash)); #else sp->_hash = (unsigned long *) calloc(lines, sizeof (*sp->_hash)); #endif if (sp->_hash == NULL) goto error2; if (0 <= __m_slk_format && __m_slk_init(sp, __m_slk_format) == ERR) { goto error2; } /* * doupdate() will perform the final screen preparations like * enter_ca_mode, reset_prog_mode() (to assert the termios * changes), etc. */ sp->_flags |= S_ENDWIN; #ifdef SIGTSTP (void) signal(SIGTSTP, tstp); #endif /* Assert that __m_screen is set to the new terminal. */ osp = set_term(sp); /* Disable echo in tty driver, Curses does software echo. */ PTERMIOS(_prog)->c_lflag &= ~ECHO; /* Enable mappnig of cr -> nl on input and nl -> crlf on output. */ PTERMIOS(_prog)->c_iflag |= ICRNL; PTERMIOS(_prog)->c_oflag |= OPOST; #ifdef ONLCR PTERMIOS(_prog)->c_oflag |= ONLCR; #endif cur_term->_flags |= __TERM_NL_IS_CRLF; #ifdef TAB0 /* Use real tabs. */ PTERMIOS(_prog)->c_oflag &= ~(TAB1|TAB2|TAB3); #endif /* * Default to 'cbreak' mode as per * test /tset/CAPIxcurses/fcbreak/fcbreak1{4} */ cur_term->_flags &= ~__TERM_HALF_DELAY; /* * Default to 'idcok' mode as per * test /tset/CAPIxcurses/fidcok/fidcok1{3} */ __m_screen->_flags |= S_INS_DEL_CHAR; PTERMIOS(_prog)->c_cc[VMIN] = 1; PTERMIOS(_prog)->c_cc[VTIME] = 0; PTERMIOS(_prog)->c_lflag &= ~ICANON; (void) __m_tty_set_prog_mode(); (void) __m_set_echo(1); (void) typeahead(fileno(in_fp)); (void) __m_slk_clear(1); n = rip.top - rip.bottom; if (stdscr == NULL) { stdscr = newwin(lines - n, 0, rip.top, 0); if (stdscr == NULL) goto error3; } /* * Create and initialise ripped off line windows. * It is the application's responsiblity to free the * windows when the application terminates. */ for (i = 0; i < n; ++i) { if (rip.line[i].created) continue; y = rip.line[i].dy; if (y < 0) y += lines; w = newwin(1, 0, y, 0); if (rip.line[i].init != (int (*)(WINDOW *, int)) 0) (void) (*rip.line[i].init)(w, columns); rip.line[i].created = 1; } LINES = stdscr->_maxy = sp->_curscr->_maxy - n; return (sp); error3: (void) set_term(osp); error2: delscreen(sp); error1: return (NULL); }