119304Speter/*- 219304Speter * Copyright (c) 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: cl_main.c,v 10.55 2011/08/15 19:52:28 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter 1919304Speter#include <bitstring.h> 2019304Speter#include <errno.h> 2119304Speter#include <fcntl.h> 2219304Speter#include <signal.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 26254225Speter#ifdef HAVE_TERM_H 27254225Speter#include <term.h> 28254225Speter#endif 2919304Speter#include <termios.h> 3019304Speter#include <unistd.h> 3119304Speter 3219304Speter#include "../common/common.h" 3319304Speter#include "cl.h" 3419304Speter#include "pathnames.h" 3519304Speter 3619304SpeterGS *__global_list; /* GLOBAL: List of screens. */ 3719304Spetersigset_t __sigblockset; /* GLOBAL: Blocked signals. */ 3819304Speter 3919304Speterstatic void cl_func_std __P((GS *)); 4019304Speterstatic CL_PRIVATE *cl_init __P((GS *)); 4119304Speterstatic GS *gs_init __P((char *)); 4219304Speterstatic void perr __P((char *, char *)); 4319304Speterstatic int setsig __P((int, struct sigaction *, void (*)(int))); 4419304Speterstatic void sig_end __P((GS *)); 4519304Speterstatic void term_init __P((char *, char *)); 4619304Speter 4719304Speter/* 4819304Speter * main -- 4919304Speter * This is the main loop for the standalone curses editor. 5019304Speter */ 5119304Speterint 52254225Spetermain(int argc, char **argv) 5319304Speter{ 5419304Speter static int reenter; 5519304Speter CL_PRIVATE *clp; 5619304Speter GS *gp; 5719304Speter size_t rows, cols; 5819304Speter int rval; 59254225Speter char **p_av, **t_av, *ttype; 6019304Speter 6119304Speter /* If loaded at 0 and jumping through a NULL pointer, stop. */ 6219304Speter if (reenter++) 6319304Speter abort(); 6419304Speter 6519304Speter /* Create and initialize the global structure. */ 6619304Speter __global_list = gp = gs_init(argv[0]); 6719304Speter 6819304Speter /* 6919304Speter * Strip out any arguments that vi isn't going to understand. There's 7019304Speter * no way to portably call getopt twice, so arguments parsed here must 7119304Speter * be removed from the argument list. 7219304Speter */ 7319304Speter for (p_av = t_av = argv;;) { 7419304Speter if (*t_av == NULL) { 7519304Speter *p_av = NULL; 7619304Speter break; 7719304Speter } 7819304Speter if (!strcmp(*t_av, "--")) { 7919304Speter while ((*p_av++ = *t_av++) != NULL); 8019304Speter break; 8119304Speter } 8219304Speter *p_av++ = *t_av++; 8319304Speter } 8419304Speter 8519304Speter /* Create and initialize the CL_PRIVATE structure. */ 8619304Speter clp = cl_init(gp); 8719304Speter 8819304Speter /* 8919304Speter * Initialize the terminal information. 9019304Speter * 9119304Speter * We have to know what terminal it is from the start, since we may 9219304Speter * have to use termcap/terminfo to find out how big the screen is. 9319304Speter */ 9419304Speter if ((ttype = getenv("TERM")) == NULL) 9519304Speter ttype = "unknown"; 9619304Speter term_init(gp->progname, ttype); 9719304Speter 9819304Speter /* Add the terminal type to the global structure. */ 9919304Speter if ((OG_D_STR(gp, GO_TERM) = 10019304Speter OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL) 10119304Speter perr(gp->progname, NULL); 10219304Speter 10319304Speter /* Figure out how big the screen is. */ 10419304Speter if (cl_ssize(NULL, 0, &rows, &cols, NULL)) 10519304Speter exit (1); 10619304Speter 10719304Speter /* Add the rows and columns to the global structure. */ 10819304Speter OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows; 10919304Speter OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols; 11019304Speter 11119304Speter /* Ex wants stdout to be buffered. */ 11219304Speter (void)setvbuf(stdout, NULL, _IOFBF, 0); 11319304Speter 11419304Speter /* Start catching signals. */ 11519304Speter if (sig_init(gp, NULL)) 11619304Speter exit (1); 11719304Speter 11819304Speter /* Run ex/vi. */ 11919304Speter rval = editor(gp, argc, argv); 12019304Speter 12119304Speter /* Clean up signals. */ 12219304Speter sig_end(gp); 12319304Speter 12419304Speter /* Clean up the terminal. */ 12519304Speter (void)cl_quit(gp); 12619304Speter 12719304Speter /* 12819304Speter * XXX 12919304Speter * Reset the O_MESG option. 13019304Speter */ 13119304Speter if (clp->tgw != TGW_UNKNOWN) 13219304Speter (void)cl_omesg(NULL, clp, clp->tgw == TGW_SET); 13319304Speter 13419304Speter /* 13519304Speter * XXX 13619304Speter * Reset the X11 xterm icon/window name. 13719304Speter */ 138254225Speter if (F_ISSET(clp, CL_RENAME)) 139254225Speter cl_setname(gp, clp->oname); 14019304Speter 14119304Speter /* If a killer signal arrived, pretend we just got it. */ 14219304Speter if (clp->killersig) { 14319304Speter (void)signal(clp->killersig, SIG_DFL); 14419304Speter (void)kill(getpid(), clp->killersig); 14519304Speter /* NOTREACHED */ 14619304Speter } 14719304Speter 14819304Speter /* Free the global and CL private areas. */ 14919304Speter#if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY) 150254225Speter if (clp->oname != NULL) 151254225Speter free(clp->oname); 15219304Speter free(clp); 153254225Speter free(OG_STR(gp, GO_TERM)); 15419304Speter free(gp); 15519304Speter#endif 15619304Speter 15719304Speter exit (rval); 15819304Speter} 15919304Speter 16019304Speter/* 16119304Speter * gs_init -- 16219304Speter * Create and partially initialize the GS structure. 16319304Speter */ 16419304Speterstatic GS * 165254225Spetergs_init(char *name) 16619304Speter{ 16719304Speter GS *gp; 16819304Speter char *p; 16919304Speter 17019304Speter /* Figure out what our name is. */ 17119304Speter if ((p = strrchr(name, '/')) != NULL) 17219304Speter name = p + 1; 17319304Speter 17419304Speter /* Allocate the global structure. */ 17519304Speter CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS)); 17619304Speter if (gp == NULL) 17719304Speter perr(name, NULL); 17819304Speter 17919304Speter gp->progname = name; 18019304Speter return (gp); 18119304Speter} 18219304Speter 18319304Speter/* 18419304Speter * cl_init -- 18519304Speter * Create and partially initialize the CL structure. 18619304Speter */ 18719304Speterstatic CL_PRIVATE * 188254225Spetercl_init(GS *gp) 18919304Speter{ 19019304Speter CL_PRIVATE *clp; 19119304Speter int fd; 19219304Speter 19319304Speter /* Allocate the CL private structure. */ 19419304Speter CALLOC_NOMSG(NULL, clp, CL_PRIVATE *, 1, sizeof(CL_PRIVATE)); 19519304Speter if (clp == NULL) 19619304Speter perr(gp->progname, NULL); 19719304Speter gp->cl_private = clp; 19819304Speter 19919304Speter /* 20019304Speter * Set the CL_STDIN_TTY flag. It's purpose is to avoid setting 20119304Speter * and resetting the tty if the input isn't from there. We also 20219304Speter * use the same test to determine if we're running a script or 20319304Speter * not. 20419304Speter */ 20519304Speter if (isatty(STDIN_FILENO)) 20619304Speter F_SET(clp, CL_STDIN_TTY); 20719304Speter else 20819304Speter F_SET(gp, G_SCRIPTED); 20919304Speter 21019304Speter /* 21119304Speter * We expect that if we've lost our controlling terminal that the 21219304Speter * open() (but not the tcgetattr()) will fail. 21319304Speter */ 21419304Speter if (F_ISSET(clp, CL_STDIN_TTY)) { 21519304Speter if (tcgetattr(STDIN_FILENO, &clp->orig) == -1) 21619304Speter goto tcfail; 21719304Speter } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) { 21819304Speter if (tcgetattr(fd, &clp->orig) == -1) { 21919304Spetertcfail: perr(gp->progname, "tcgetattr"); 22019304Speter exit (1); 22119304Speter } 22219304Speter (void)close(fd); 22319304Speter } 22419304Speter 22519304Speter /* Initialize the list of curses functions. */ 22619304Speter cl_func_std(gp); 22719304Speter 22819304Speter return (clp); 22919304Speter} 23019304Speter 23119304Speter/* 23219304Speter * term_init -- 23319304Speter * Initialize terminal information. 23419304Speter */ 23519304Speterstatic void 236254225Speterterm_init(char *name, char *ttype) 23719304Speter{ 23819304Speter int err; 23919304Speter 24019304Speter /* Set up the terminal database information. */ 24119304Speter setupterm(ttype, STDOUT_FILENO, &err); 24219304Speter switch (err) { 24319304Speter case -1: 24419304Speter (void)fprintf(stderr, 24519304Speter "%s: No terminal database found\n", name); 24619304Speter exit (1); 24719304Speter case 0: 24819304Speter (void)fprintf(stderr, 24919304Speter "%s: %s: unknown terminal type\n", name, ttype); 25019304Speter exit (1); 25119304Speter } 25219304Speter} 25319304Speter 25419304Speter#define GLOBAL_CLP \ 25519304Speter CL_PRIVATE *clp = GCLP(__global_list); 25619304Speterstatic void 257254225Speterh_hup(int signo) 25819304Speter{ 25919304Speter GLOBAL_CLP; 26019304Speter 26119304Speter F_SET(clp, CL_SIGHUP); 26219304Speter clp->killersig = SIGHUP; 26319304Speter} 26419304Speter 26519304Speterstatic void 266254225Speterh_int(int signo) 26719304Speter{ 26819304Speter GLOBAL_CLP; 26919304Speter 27019304Speter F_SET(clp, CL_SIGINT); 27119304Speter} 27219304Speter 27319304Speterstatic void 274254225Speterh_term(int signo) 27519304Speter{ 27619304Speter GLOBAL_CLP; 27719304Speter 27819304Speter F_SET(clp, CL_SIGTERM); 27919304Speter clp->killersig = SIGTERM; 28019304Speter} 28119304Speter 28219304Speterstatic void 283254225Speterh_winch(int signo) 28419304Speter{ 28519304Speter GLOBAL_CLP; 28619304Speter 28719304Speter F_SET(clp, CL_SIGWINCH); 28819304Speter} 28919304Speter#undef GLOBAL_CLP 29019304Speter 29119304Speter/* 29219304Speter * sig_init -- 29319304Speter * Initialize signals. 29419304Speter * 29519304Speter * PUBLIC: int sig_init __P((GS *, SCR *)); 29619304Speter */ 29719304Speterint 298254225Spetersig_init(GS *gp, SCR *sp) 29919304Speter{ 30019304Speter CL_PRIVATE *clp; 30119304Speter 30219304Speter clp = GCLP(gp); 30319304Speter 30419304Speter if (sp == NULL) { 30519304Speter (void)sigemptyset(&__sigblockset); 30619304Speter if (sigaddset(&__sigblockset, SIGHUP) || 30719304Speter setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) || 30819304Speter sigaddset(&__sigblockset, SIGINT) || 30919304Speter setsig(SIGINT, &clp->oact[INDX_INT], h_int) || 31019304Speter sigaddset(&__sigblockset, SIGTERM) || 31119304Speter setsig(SIGTERM, &clp->oact[INDX_TERM], h_term) 31219304Speter#ifdef SIGWINCH 31319304Speter || 31419304Speter sigaddset(&__sigblockset, SIGWINCH) || 31519304Speter setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch) 31619304Speter#endif 31719304Speter ) { 31819304Speter perr(gp->progname, NULL); 31919304Speter return (1); 32019304Speter } 32119304Speter } else 32219304Speter if (setsig(SIGHUP, NULL, h_hup) || 32319304Speter setsig(SIGINT, NULL, h_int) || 32419304Speter setsig(SIGTERM, NULL, h_term) 32519304Speter#ifdef SIGWINCH 32619304Speter || 32719304Speter setsig(SIGWINCH, NULL, h_winch) 32819304Speter#endif 32919304Speter ) { 33019304Speter msgq(sp, M_SYSERR, "signal-reset"); 33119304Speter } 33219304Speter return (0); 33319304Speter} 33419304Speter 33519304Speter/* 33619304Speter * setsig -- 33719304Speter * Set a signal handler. 33819304Speter */ 33919304Speterstatic int 340254225Spetersetsig(int signo, struct sigaction *oactp, void (*handler) (int)) 34119304Speter{ 34219304Speter struct sigaction act; 34319304Speter 34419304Speter /* 34519304Speter * Use sigaction(2), not signal(3), since we don't always want to 34619304Speter * restart system calls. The example is when waiting for a command 34719304Speter * mode keystroke and SIGWINCH arrives. Besides, you can't portably 34819304Speter * restart system calls (thanks, POSIX!). On the other hand, you 34919304Speter * can't portably NOT restart system calls (thanks, Sun!). SunOS 35019304Speter * used SA_INTERRUPT as their extension to NOT restart read calls. 35119304Speter * We sure hope nobody else used it for anything else. Mom told me 35219304Speter * there'd be days like this. She just never told me that there'd 35319304Speter * be so many. 35419304Speter */ 35519304Speter act.sa_handler = handler; 35619304Speter sigemptyset(&act.sa_mask); 35719304Speter 35819304Speter#ifdef SA_INTERRUPT 35919304Speter act.sa_flags = SA_INTERRUPT; 36019304Speter#else 36119304Speter act.sa_flags = 0; 36219304Speter#endif 36319304Speter return (sigaction(signo, &act, oactp)); 36419304Speter} 36519304Speter 36619304Speter/* 36719304Speter * sig_end -- 36819304Speter * End signal setup. 36919304Speter */ 37019304Speterstatic void 371254225Spetersig_end(GS *gp) 37219304Speter{ 37319304Speter CL_PRIVATE *clp; 37419304Speter 37519304Speter clp = GCLP(gp); 37619304Speter (void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]); 37719304Speter (void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]); 37819304Speter (void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]); 37919304Speter#ifdef SIGWINCH 38019304Speter (void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]); 38119304Speter#endif 38219304Speter} 38319304Speter 38419304Speter/* 38519304Speter * cl_func_std -- 38619304Speter * Initialize the standard curses functions. 38719304Speter */ 38819304Speterstatic void 389254225Spetercl_func_std(GS *gp) 39019304Speter{ 39119304Speter gp->scr_addstr = cl_addstr; 392254225Speter gp->scr_waddstr = cl_waddstr; 39319304Speter gp->scr_attr = cl_attr; 39419304Speter gp->scr_baud = cl_baud; 39519304Speter gp->scr_bell = cl_bell; 39619304Speter gp->scr_busy = NULL; 397254225Speter gp->scr_child = NULL; 39819304Speter gp->scr_clrtoeol = cl_clrtoeol; 39919304Speter gp->scr_cursor = cl_cursor; 40019304Speter gp->scr_deleteln = cl_deleteln; 401254225Speter gp->scr_reply = NULL; 402254225Speter gp->scr_discard = cl_discard; 40319304Speter gp->scr_event = cl_event; 40419304Speter gp->scr_ex_adjust = cl_ex_adjust; 40519304Speter gp->scr_fmap = cl_fmap; 40619304Speter gp->scr_insertln = cl_insertln; 40719304Speter gp->scr_keyval = cl_keyval; 40819304Speter gp->scr_move = cl_move; 40919304Speter gp->scr_msg = NULL; 41019304Speter gp->scr_optchange = cl_optchange; 41119304Speter gp->scr_refresh = cl_refresh; 41219304Speter gp->scr_rename = cl_rename; 41319304Speter gp->scr_screen = cl_screen; 414254225Speter gp->scr_split = cl_split; 41519304Speter gp->scr_suspend = cl_suspend; 41619304Speter gp->scr_usage = cl_usage; 41719304Speter} 41819304Speter 41919304Speter/* 42019304Speter * perr -- 42119304Speter * Print system error. 42219304Speter */ 42319304Speterstatic void 424254225Speterperr(char *name, char *msg) 42519304Speter{ 42619304Speter (void)fprintf(stderr, "%s:", name); 42719304Speter if (msg != NULL) 42819304Speter (void)fprintf(stderr, "%s:", msg); 42919304Speter (void)fprintf(stderr, "%s\n", strerror(errno)); 43019304Speter exit(1); 43119304Speter} 432