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[] = "@(#)cl_main.c 10.36 (Berkeley) 10/14/96";
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #include <bitstring.h>
30 #include "../common/common.h"
35 #include "pathnames.h"
37 GS *__global_list; /* GLOBAL: List of screens. */
38 sigset_t __sigblockset; /* GLOBAL: Blocked signals. */
40 static void cl_func_std __P((GS *));
41 static CL_PRIVATE *cl_init __P((GS *));
42 static GS *gs_init __P((char *));
43 static void perr __P((char *, char *));
44 static int setsig __P((int, struct sigaction *, void (*)(int)));
45 static void sig_end __P((GS *));
46 static void term_init __P((char *, char *));
50 * This is the main loop for the standalone curses editor.
62 char *ip_arg, **p_av, **t_av, *ttype;
64 /* If loaded at 0 and jumping through a NULL pointer, stop. */
68 /* Create and initialize the global structure. */
69 __global_list = gp = gs_init(argv[0]);
72 * Strip out any arguments that vi isn't going to understand. There's
73 * no way to portably call getopt twice, so arguments parsed here must
74 * be removed from the argument list.
78 for (p_av = t_av = argv;;) {
83 if (!strcmp(*t_av, "--")) {
84 while ((*p_av++ = *t_av++) != NULL);
87 if (!memcmp(*t_av, "-I", sizeof("-I") - 1)) {
88 if (t_av[0][2] != '\0') {
94 if (t_av[1] != NULL) {
105 * If we're being called as an editor library, we're done here, we
106 * get loaded with the curses screen, we don't share much code.
109 exit (ip_main(argc, argv, gp, ip_arg));
114 /* Create and initialize the CL_PRIVATE structure. */
118 * Initialize the terminal information.
120 * We have to know what terminal it is from the start, since we may
121 * have to use termcap/terminfo to find out how big the screen is.
123 if ((ttype = getenv("TERM")) == NULL)
125 term_init(gp->progname, ttype);
127 /* Add the terminal type to the global structure. */
128 if ((OG_D_STR(gp, GO_TERM) =
129 OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL)
130 perr(gp->progname, NULL);
132 /* Figure out how big the screen is. */
133 if (cl_ssize(NULL, 0, &rows, &cols, NULL))
136 /* Add the rows and columns to the global structure. */
137 OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows;
138 OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols;
140 /* Ex wants stdout to be buffered. */
141 (void)setvbuf(stdout, NULL, _IOFBF, 0);
143 /* Start catching signals. */
144 if (sig_init(gp, NULL))
148 rval = editor(gp, argc, argv);
150 /* Clean up signals. */
153 /* Clean up the terminal. */
158 * Reset the O_MESG option.
160 if (clp->tgw != TGW_UNKNOWN)
161 (void)cl_omesg(NULL, clp, clp->tgw == TGW_SET);
165 * Reset the X11 xterm icon/window name.
167 if (F_ISSET(clp, CL_RENAME)) {
168 (void)printf(XTERM_RENAME, ttype);
169 (void)fflush(stdout);
172 /* If a killer signal arrived, pretend we just got it. */
173 if (clp->killersig) {
174 (void)signal(clp->killersig, SIG_DFL);
175 (void)kill(getpid(), clp->killersig);
179 /* Free the global and CL private areas. */
180 #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
190 * Create and partially initialize the GS structure.
200 /* Figure out what our name is. */
201 if ((p = strrchr(name, '/')) != NULL)
204 /* Allocate the global structure. */
205 CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS));
216 * Create and partially initialize the CL structure.
225 /* Allocate the CL private structure. */
226 CALLOC_NOMSG(NULL, clp, CL_PRIVATE *, 1, sizeof(CL_PRIVATE));
228 perr(gp->progname, NULL);
229 gp->cl_private = clp;
232 * Set the CL_STDIN_TTY flag. It's purpose is to avoid setting
233 * and resetting the tty if the input isn't from there. We also
234 * use the same test to determine if we're running a script or
237 if (isatty(STDIN_FILENO))
238 F_SET(clp, CL_STDIN_TTY);
240 F_SET(gp, G_SCRIPTED);
243 * We expect that if we've lost our controlling terminal that the
244 * open() (but not the tcgetattr()) will fail.
246 if (F_ISSET(clp, CL_STDIN_TTY)) {
247 if (tcgetattr(STDIN_FILENO, &clp->orig) == -1)
249 } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
250 if (tcgetattr(fd, &clp->orig) == -1) {
251 tcfail: perr(gp->progname, "tcgetattr");
257 /* Initialize the list of curses functions. */
265 * Initialize terminal information.
268 term_init(name, ttype)
273 /* Set up the terminal database information. */
274 setupterm(ttype, STDOUT_FILENO, &err);
277 (void)fprintf(stderr,
278 "%s: No terminal database found\n", name);
281 (void)fprintf(stderr,
282 "%s: %s: unknown terminal type\n", name, ttype);
288 CL_PRIVATE *clp = GCLP(__global_list);
295 F_SET(clp, CL_SIGHUP);
296 clp->killersig = SIGHUP;
305 F_SET(clp, CL_SIGINT);
314 F_SET(clp, CL_SIGTERM);
315 clp->killersig = SIGTERM;
324 F_SET(clp, CL_SIGWINCH);
330 * Initialize signals.
332 * PUBLIC: int sig_init __P((GS *, SCR *));
344 (void)sigemptyset(&__sigblockset);
345 if (sigaddset(&__sigblockset, SIGHUP) ||
346 setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) ||
347 sigaddset(&__sigblockset, SIGINT) ||
348 setsig(SIGINT, &clp->oact[INDX_INT], h_int) ||
349 sigaddset(&__sigblockset, SIGTERM) ||
350 setsig(SIGTERM, &clp->oact[INDX_TERM], h_term)
353 sigaddset(&__sigblockset, SIGWINCH) ||
354 setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch)
357 perr(gp->progname, NULL);
361 if (setsig(SIGHUP, NULL, h_hup) ||
362 setsig(SIGINT, NULL, h_int) ||
363 setsig(SIGTERM, NULL, h_term)
366 setsig(SIGWINCH, NULL, h_winch)
369 msgq(sp, M_SYSERR, "signal-reset");
376 * Set a signal handler.
379 setsig(signo, oactp, handler)
381 struct sigaction *oactp;
382 void (*handler) __P((int));
384 struct sigaction act;
387 * Use sigaction(2), not signal(3), since we don't always want to
388 * restart system calls. The example is when waiting for a command
389 * mode keystroke and SIGWINCH arrives. Besides, you can't portably
390 * restart system calls (thanks, POSIX!). On the other hand, you
391 * can't portably NOT restart system calls (thanks, Sun!). SunOS
392 * used SA_INTERRUPT as their extension to NOT restart read calls.
393 * We sure hope nobody else used it for anything else. Mom told me
394 * there'd be days like this. She just never told me that there'd
397 act.sa_handler = handler;
398 sigemptyset(&act.sa_mask);
401 act.sa_flags = SA_INTERRUPT;
405 return (sigaction(signo, &act, oactp));
419 (void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]);
420 (void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]);
421 (void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]);
423 (void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]);
429 * Initialize the standard curses functions.
435 gp->scr_addstr = cl_addstr;
436 gp->scr_attr = cl_attr;
437 gp->scr_baud = cl_baud;
438 gp->scr_bell = cl_bell;
440 gp->scr_clrtoeol = cl_clrtoeol;
441 gp->scr_cursor = cl_cursor;
442 gp->scr_deleteln = cl_deleteln;
443 gp->scr_event = cl_event;
444 gp->scr_ex_adjust = cl_ex_adjust;
445 gp->scr_fmap = cl_fmap;
446 gp->scr_insertln = cl_insertln;
447 gp->scr_keyval = cl_keyval;
448 gp->scr_move = cl_move;
450 gp->scr_optchange = cl_optchange;
451 gp->scr_refresh = cl_refresh;
452 gp->scr_rename = cl_rename;
453 gp->scr_screen = cl_screen;
454 gp->scr_suspend = cl_suspend;
455 gp->scr_usage = cl_usage;
460 * Print system error.
466 (void)fprintf(stderr, "%s:", name);
468 (void)fprintf(stderr, "%s:", msg);
469 (void)fprintf(stderr, "%s\n", strerror(errno));