include <term.h> for setupterm(), tputs() and tgoto()
[nvi.git] / cl / cl_main.c
blob62aabe988908f1c0d730c191d418fc5ac141ad9e
1 /*-
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.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: cl_main.c,v 10.54 2001/07/29 19:07:27 skimo Exp $ (Berkeley) $Date: 2001/07/29 19:07:27 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #include <bitstring.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <term.h>
27 #include <termios.h>
28 #include <unistd.h>
30 #include "../common/common.h"
31 #include "../ip/extern.h"
32 #include "cl.h"
33 #include "pathnames.h"
35 GS *__global_list; /* GLOBAL: List of screens. */
36 sigset_t __sigblockset; /* GLOBAL: Blocked signals. */
38 static void cl_func_std __P((WIN *));
39 static void cl_end __P((CL_PRIVATE *));
40 static CL_PRIVATE *cl_init __P((WIN *));
41 static void perr __P((char *, char *));
42 static int setsig __P((int, struct sigaction *, void (*)(int)));
43 static void sig_end __P((GS *));
44 static void term_init __P((char *, char *));
47 * main --
48 * This is the main loop for the standalone curses editor.
50 int
51 main(int argc, char **argv)
53 static int reenter;
54 CL_PRIVATE *clp;
55 GS *gp;
56 WIN *wp;
57 size_t rows, cols;
58 int rval;
59 char **p_av, **t_av, *ttype;
61 /* If loaded at 0 and jumping through a NULL pointer, stop. */
62 if (reenter++)
63 abort();
65 /* Create and initialize the global structure. */
66 __global_list = gp = gs_init(argv[0]);
69 * Strip out any arguments that vi isn't going to understand. There's
70 * no way to portably call getopt twice, so arguments parsed here must
71 * be removed from the argument list.
73 for (p_av = t_av = argv;;) {
74 if (*t_av == NULL) {
75 *p_av = NULL;
76 break;
78 if (!strcmp(*t_av, "--")) {
79 while ((*p_av++ = *t_av++) != NULL);
80 break;
82 *p_av++ = *t_av++;
85 /* Create new window */
86 wp = gs_new_win(gp);
88 /* Create and initialize the CL_PRIVATE structure. */
89 clp = cl_init(wp);
92 * Initialize the terminal information.
94 * We have to know what terminal it is from the start, since we may
95 * have to use termcap/terminfo to find out how big the screen is.
97 if ((ttype = getenv("TERM")) == NULL)
98 ttype = "unknown";
99 term_init(gp->progname, ttype);
101 /* Add the terminal type to the global structure. */
102 if ((OG_D_STR(gp, GO_TERM) =
103 OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL)
104 perr(gp->progname, NULL);
106 /* Figure out how big the screen is. */
107 if (cl_ssize(NULL, 0, &rows, &cols, NULL))
108 exit (1);
110 /* Add the rows and columns to the global structure. */
111 OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows;
112 OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols;
114 /* Ex wants stdout to be buffered. */
115 (void)setvbuf(stdout, NULL, _IOFBF, 0);
117 /* Start catching signals. */
118 if (sig_init(gp, NULL))
119 exit (1);
121 /* Run ex/vi. */
122 rval = editor(wp, argc, argv);
124 /* Clean out the global structure. */
125 gs_end(gp);
127 /* Clean up signals. */
128 sig_end(gp);
130 /* Clean up the terminal. */
131 (void)cl_quit(gp);
134 * XXX
135 * Reset the O_MESG option.
137 if (clp->tgw != TGW_UNKNOWN)
138 (void)cl_omesg(NULL, clp, clp->tgw == TGW_SET);
141 * XXX
142 * Reset the X11 xterm icon/window name.
144 if (F_ISSET(clp, CL_RENAME))
145 cl_setname(gp, clp->oname);
147 /* If a killer signal arrived, pretend we just got it. */
148 if (clp->killersig) {
149 (void)signal(clp->killersig, SIG_DFL);
150 (void)kill(getpid(), clp->killersig);
151 /* NOTREACHED */
154 /* Free the global and CL private areas. */
155 #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
156 cl_end(clp);
157 free(gp);
158 #endif
160 exit (rval);
164 * cl_init --
165 * Create and partially initialize the CL structure.
167 static CL_PRIVATE *
168 cl_init(WIN *wp)
170 CL_PRIVATE *clp;
171 int fd;
172 GS *gp;
174 gp = wp->gp;
176 /* Allocate the CL private structure. */
177 CALLOC_NOMSG(NULL, clp, CL_PRIVATE *, 1, sizeof(CL_PRIVATE));
178 if (clp == NULL)
179 perr(gp->progname, NULL);
180 gp->cl_private = clp;
183 * Set the CL_STDIN_TTY flag. It's purpose is to avoid setting
184 * and resetting the tty if the input isn't from there. We also
185 * use the same test to determine if we're running a script or
186 * not.
188 if (isatty(STDIN_FILENO))
189 F_SET(clp, CL_STDIN_TTY);
190 else
191 F_SET(gp, G_SCRIPTED);
194 * We expect that if we've lost our controlling terminal that the
195 * open() (but not the tcgetattr()) will fail.
197 if (F_ISSET(clp, CL_STDIN_TTY)) {
198 if (tcgetattr(STDIN_FILENO, &clp->orig) == -1)
199 goto tcfail;
200 } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
201 if (tcgetattr(fd, &clp->orig) == -1) {
202 tcfail: perr(gp->progname, "tcgetattr");
203 exit (1);
205 (void)close(fd);
208 /* Initialize the list of curses functions. */
209 cl_func_std(wp);
211 return (clp);
215 * cl_end --
216 * Discard the CL structure.
218 static void
219 cl_end(CL_PRIVATE *clp)
221 if (clp->oname != NULL)
222 free(clp->oname);
223 free(clp);
227 * term_init --
228 * Initialize terminal information.
230 static void
231 term_init(char *name, char *ttype)
233 int err;
235 /* Set up the terminal database information. */
236 setupterm(ttype, STDOUT_FILENO, &err);
237 switch (err) {
238 case -1:
239 (void)fprintf(stderr,
240 "%s: No terminal database found\n", name);
241 exit (1);
242 case 0:
243 (void)fprintf(stderr,
244 "%s: %s: unknown terminal type\n", name, ttype);
245 exit (1);
249 #define GLOBAL_CLP \
250 CL_PRIVATE *clp = GCLP(__global_list);
251 static void
252 h_hup(int signo)
254 GLOBAL_CLP;
256 F_SET(clp, CL_SIGHUP);
257 clp->killersig = SIGHUP;
260 static void
261 h_int(int signo)
263 GLOBAL_CLP;
265 F_SET(clp, CL_SIGINT);
268 static void
269 h_term(int signo)
271 GLOBAL_CLP;
273 F_SET(clp, CL_SIGTERM);
274 clp->killersig = SIGTERM;
277 static void
278 h_winch(int signo)
280 GLOBAL_CLP;
282 F_SET(clp, CL_SIGWINCH);
284 #undef GLOBAL_CLP
287 * sig_init --
288 * Initialize signals.
290 * PUBLIC: int sig_init __P((GS *, SCR *));
293 sig_init(GS *gp, SCR *sp)
295 CL_PRIVATE *clp;
297 clp = GCLP(gp);
299 if (sp == NULL) {
300 (void)sigemptyset(&__sigblockset);
301 if (sigaddset(&__sigblockset, SIGHUP) ||
302 setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) ||
303 sigaddset(&__sigblockset, SIGINT) ||
304 setsig(SIGINT, &clp->oact[INDX_INT], h_int) ||
305 sigaddset(&__sigblockset, SIGTERM) ||
306 setsig(SIGTERM, &clp->oact[INDX_TERM], h_term)
307 #ifdef SIGWINCH
309 sigaddset(&__sigblockset, SIGWINCH) ||
310 setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch)
311 #endif
313 perr(gp->progname, NULL);
314 return (1);
316 } else
317 if (setsig(SIGHUP, NULL, h_hup) ||
318 setsig(SIGINT, NULL, h_int) ||
319 setsig(SIGTERM, NULL, h_term)
320 #ifdef SIGWINCH
322 setsig(SIGWINCH, NULL, h_winch)
323 #endif
325 msgq(sp, M_SYSERR, "signal-reset");
327 return (0);
331 * setsig --
332 * Set a signal handler.
334 static int
335 setsig(int signo, struct sigaction *oactp, void (*handler) (int))
337 struct sigaction act;
340 * Use sigaction(2), not signal(3), since we don't always want to
341 * restart system calls. The example is when waiting for a command
342 * mode keystroke and SIGWINCH arrives. Besides, you can't portably
343 * restart system calls (thanks, POSIX!). On the other hand, you
344 * can't portably NOT restart system calls (thanks, Sun!). SunOS
345 * used SA_INTERRUPT as their extension to NOT restart read calls.
346 * We sure hope nobody else used it for anything else. Mom told me
347 * there'd be days like this. She just never told me that there'd
348 * be so many.
350 act.sa_handler = handler;
351 sigemptyset(&act.sa_mask);
353 #ifdef SA_INTERRUPT
354 act.sa_flags = SA_INTERRUPT;
355 #else
356 act.sa_flags = 0;
357 #endif
358 return (sigaction(signo, &act, oactp));
362 * sig_end --
363 * End signal setup.
365 static void
366 sig_end(GS *gp)
368 CL_PRIVATE *clp;
370 clp = GCLP(gp);
371 (void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]);
372 (void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]);
373 (void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]);
374 #ifdef SIGWINCH
375 (void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]);
376 #endif
380 * cl_func_std --
381 * Initialize the standard curses functions.
383 static void
384 cl_func_std(WIN *wp)
386 GS *gp;
388 gp = wp->gp;
390 gp->scr_addstr = cl_addstr;
391 gp->scr_waddstr = cl_waddstr;
392 gp->scr_attr = cl_attr;
393 gp->scr_baud = cl_baud;
394 gp->scr_bell = cl_bell;
395 gp->scr_busy = NULL;
396 gp->scr_child = NULL;
397 gp->scr_clrtoeol = cl_clrtoeol;
398 gp->scr_cursor = cl_cursor;
399 gp->scr_deleteln = cl_deleteln;
400 gp->scr_reply = NULL;
401 gp->scr_discard = cl_discard;
402 gp->scr_event = cl_event;
403 gp->scr_ex_adjust = cl_ex_adjust;
404 gp->scr_fmap = cl_fmap;
405 gp->scr_insertln = cl_insertln;
406 gp->scr_keyval = cl_keyval;
407 gp->scr_move = cl_move;
408 wp->scr_msg = NULL;
409 gp->scr_optchange = cl_optchange;
410 gp->scr_refresh = cl_refresh;
411 gp->scr_rename = cl_rename;
412 gp->scr_screen = cl_screen;
413 gp->scr_split = cl_split;
414 gp->scr_suspend = cl_suspend;
415 gp->scr_usage = cl_usage;
419 * perr --
420 * Print system error.
422 static void
423 perr(char *name, char *msg)
425 (void)fprintf(stderr, "%s:", name);
426 if (msg != NULL)
427 (void)fprintf(stderr, "%s:", msg);
428 (void)fprintf(stderr, "%s\n", strerror(errno));
429 exit(1);