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