Scott Bolte's fixes for C++ comments.
[nvi.git] / cl / cl_main.c
blob247b85a4cb6a7965719f643102cf58678b3a711e
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.45 1996/12/18 17:06:41 bostic Exp $ (Berkeley) $Date: 1996/12/18 17:06:41 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #include <bitstring.h>
20 #include <curses.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.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((GS *));
39 static void cl_end __P((CL_PRIVATE *));
40 static CL_PRIVATE *cl_init __P((GS *));
41 static GS *gs_init __P((char *));
42 static void perr __P((char *, char *));
43 static int setsig __P((int, struct sigaction *, void (*)(int)));
44 static void sig_end __P((GS *));
45 static void term_init __P((char *, char *));
48 * main --
49 * This is the main loop for the standalone curses editor.
51 int
52 main(argc, argv)
53 int argc;
54 char *argv[];
56 static int reenter;
57 CL_PRIVATE *clp;
58 GS *gp;
59 size_t rows, cols;
60 int rval;
61 char *ip_arg, **p_av, **t_av, *ttype;
63 /* If loaded at 0 and jumping through a NULL pointer, stop. */
64 if (reenter++)
65 abort();
67 /* Create and initialize the global structure. */
68 __global_list = gp = gs_init(argv[0]);
71 * Strip out any arguments that vi isn't going to understand. There's
72 * no way to portably call getopt twice, so arguments parsed here must
73 * be removed from the argument list.
75 ip_arg = NULL;
76 for (p_av = t_av = argv;;) {
77 if (*t_av == NULL) {
78 *p_av = NULL;
79 break;
81 if (!strcmp(*t_av, "--")) {
82 while ((*p_av++ = *t_av++) != NULL);
83 break;
85 if (!memcmp(*t_av, "-I", sizeof("-I") - 1)) {
86 if (t_av[0][2] != '\0') {
87 ip_arg = t_av[0] + 2;
88 ++t_av;
89 --argc;
90 continue;
92 if (t_av[1] != NULL) {
93 ip_arg = t_av[1];
94 t_av += 2;
95 argc -= 2;
96 continue;
99 *p_av++ = *t_av++;
103 * If we're being called as an editor library, we're done here, we
104 * get loaded with the curses screen, we don't share much code.
106 if (ip_arg != NULL)
107 exit (ip_main(argc, argv, gp, ip_arg));
109 /* Create and initialize the CL_PRIVATE structure. */
110 clp = cl_init(gp);
113 * Initialize the terminal information.
115 * We have to know what terminal it is from the start, since we may
116 * have to use termcap/terminfo to find out how big the screen is.
118 if ((ttype = getenv("TERM")) == NULL)
119 ttype = "unknown";
120 term_init(gp->progname, ttype);
122 /* Add the terminal type to the global structure. */
123 if ((OG_D_STR(gp, GO_TERM) =
124 OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL)
125 perr(gp->progname, NULL);
127 /* Figure out how big the screen is. */
128 if (cl_ssize(NULL, 0, &rows, &cols, NULL))
129 exit (1);
131 /* Add the rows and columns to the global structure. */
132 OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows;
133 OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols;
135 /* Ex wants stdout to be buffered. */
136 (void)setvbuf(stdout, NULL, _IOFBF, 0);
138 /* Start catching signals. */
139 if (sig_init(gp, NULL))
140 exit (1);
142 /* Run ex/vi. */
143 rval = editor(gp, argc, argv);
145 /* Clean up signals. */
146 sig_end(gp);
148 /* Clean up the terminal. */
149 (void)cl_quit(gp);
152 * XXX
153 * Reset the O_MESG option.
155 if (clp->tgw != TGW_UNKNOWN)
156 (void)cl_omesg(NULL, clp, clp->tgw == TGW_SET);
159 * XXX
160 * Reset the X11 xterm icon/window name.
162 if (F_ISSET(clp, CL_RENAME))
163 cl_setname(gp, clp->oname);
165 /* If a killer signal arrived, pretend we just got it. */
166 if (clp->killersig) {
167 (void)signal(clp->killersig, SIG_DFL);
168 (void)kill(getpid(), clp->killersig);
169 /* NOTREACHED */
172 /* Free the global and CL private areas. */
173 #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
174 cl_end(clp);
175 free(gp);
176 #endif
178 exit (rval);
182 * gs_init --
183 * Create and partially initialize the GS structure.
185 static GS *
186 gs_init(name)
187 char *name;
189 GS *gp;
190 char *p;
192 /* Figure out what our name is. */
193 if ((p = strrchr(name, '/')) != NULL)
194 name = p + 1;
196 /* Allocate the global structure. */
197 CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS));
198 if (gp == NULL)
199 perr(name, NULL);
202 gp->progname = name;
203 return (gp);
207 * cl_init --
208 * Create and partially initialize the CL structure.
210 static CL_PRIVATE *
211 cl_init(gp)
212 GS *gp;
214 CL_PRIVATE *clp;
215 int fd;
217 /* Allocate the CL private structure. */
218 CALLOC_NOMSG(NULL, clp, CL_PRIVATE *, 1, sizeof(CL_PRIVATE));
219 if (clp == NULL)
220 perr(gp->progname, NULL);
221 gp->cl_private = clp;
224 * Set the CL_STDIN_TTY flag. It's purpose is to avoid setting
225 * and resetting the tty if the input isn't from there. We also
226 * use the same test to determine if we're running a script or
227 * not.
229 if (isatty(STDIN_FILENO))
230 F_SET(clp, CL_STDIN_TTY);
231 else
232 F_SET(gp, G_SCRIPTED);
235 * We expect that if we've lost our controlling terminal that the
236 * open() (but not the tcgetattr()) will fail.
238 if (F_ISSET(clp, CL_STDIN_TTY)) {
239 if (tcgetattr(STDIN_FILENO, &clp->orig) == -1)
240 goto tcfail;
241 } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
242 if (tcgetattr(fd, &clp->orig) == -1) {
243 tcfail: perr(gp->progname, "tcgetattr");
244 exit (1);
246 (void)close(fd);
249 /* Initialize the list of curses functions. */
250 cl_func_std(gp);
252 return (clp);
256 * cl_end --
257 * Discard the CL structure.
259 static void
260 cl_end(clp)
261 CL_PRIVATE *clp;
263 if (clp->oname != NULL)
264 free(clp->oname);
265 free(clp);
269 * term_init --
270 * Initialize terminal information.
272 static void
273 term_init(name, ttype)
274 char *name, *ttype;
276 int err;
278 /* Set up the terminal database information. */
279 setupterm(ttype, STDOUT_FILENO, &err);
280 switch (err) {
281 case -1:
282 (void)fprintf(stderr,
283 "%s: No terminal database found\n", name);
284 exit (1);
285 case 0:
286 (void)fprintf(stderr,
287 "%s: %s: unknown terminal type\n", name, ttype);
288 exit (1);
292 #define GLOBAL_CLP \
293 CL_PRIVATE *clp = GCLP(__global_list);
294 static void
295 h_hup(signo)
296 int signo;
298 GLOBAL_CLP;
300 F_SET(clp, CL_SIGHUP);
301 clp->killersig = SIGHUP;
304 static void
305 h_int(signo)
306 int signo;
308 GLOBAL_CLP;
310 F_SET(clp, CL_SIGINT);
313 static void
314 h_term(signo)
315 int signo;
317 GLOBAL_CLP;
319 F_SET(clp, CL_SIGTERM);
320 clp->killersig = SIGTERM;
323 static void
324 h_winch(signo)
325 int signo;
327 GLOBAL_CLP;
329 F_SET(clp, CL_SIGWINCH);
331 #undef GLOBAL_CLP
334 * sig_init --
335 * Initialize signals.
337 * PUBLIC: int sig_init __P((GS *, SCR *));
340 sig_init(gp, sp)
341 GS *gp;
342 SCR *sp;
344 CL_PRIVATE *clp;
346 clp = GCLP(gp);
348 if (sp == NULL) {
349 (void)sigemptyset(&__sigblockset);
350 if (sigaddset(&__sigblockset, SIGHUP) ||
351 setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) ||
352 sigaddset(&__sigblockset, SIGINT) ||
353 setsig(SIGINT, &clp->oact[INDX_INT], h_int) ||
354 sigaddset(&__sigblockset, SIGTERM) ||
355 setsig(SIGTERM, &clp->oact[INDX_TERM], h_term)
356 #ifdef SIGWINCH
358 sigaddset(&__sigblockset, SIGWINCH) ||
359 setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch)
360 #endif
362 perr(gp->progname, NULL);
363 return (1);
365 } else
366 if (setsig(SIGHUP, NULL, h_hup) ||
367 setsig(SIGINT, NULL, h_int) ||
368 setsig(SIGTERM, NULL, h_term)
369 #ifdef SIGWINCH
371 setsig(SIGWINCH, NULL, h_winch)
372 #endif
374 msgq(sp, M_SYSERR, "signal-reset");
376 return (0);
380 * setsig --
381 * Set a signal handler.
383 static int
384 setsig(signo, oactp, handler)
385 int signo;
386 struct sigaction *oactp;
387 void (*handler) __P((int));
389 struct sigaction act;
392 * Use sigaction(2), not signal(3), since we don't always want to
393 * restart system calls. The example is when waiting for a command
394 * mode keystroke and SIGWINCH arrives. Besides, you can't portably
395 * restart system calls (thanks, POSIX!). On the other hand, you
396 * can't portably NOT restart system calls (thanks, Sun!). SunOS
397 * used SA_INTERRUPT as their extension to NOT restart read calls.
398 * We sure hope nobody else used it for anything else. Mom told me
399 * there'd be days like this. She just never told me that there'd
400 * be so many.
402 act.sa_handler = handler;
403 sigemptyset(&act.sa_mask);
405 #ifdef SA_INTERRUPT
406 act.sa_flags = SA_INTERRUPT;
407 #else
408 act.sa_flags = 0;
409 #endif
410 return (sigaction(signo, &act, oactp));
414 * sig_end --
415 * End signal setup.
417 static void
418 sig_end(gp)
419 GS *gp;
421 CL_PRIVATE *clp;
423 clp = GCLP(gp);
424 (void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]);
425 (void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]);
426 (void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]);
427 #ifdef SIGWINCH
428 (void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]);
429 #endif
433 * cl_func_std --
434 * Initialize the standard curses functions.
436 static void
437 cl_func_std(gp)
438 GS *gp;
440 gp->scr_addstr = cl_addstr;
441 gp->scr_attr = cl_attr;
442 gp->scr_baud = cl_baud;
443 gp->scr_bell = cl_bell;
444 gp->scr_busy = NULL;
445 gp->scr_clrtoeol = cl_clrtoeol;
446 gp->scr_cursor = cl_cursor;
447 gp->scr_deleteln = cl_deleteln;
448 gp->scr_discard = cl_discard;
449 gp->scr_event = cl_event;
450 gp->scr_ex_adjust = cl_ex_adjust;
451 gp->scr_fmap = cl_fmap;
452 gp->scr_insertln = cl_insertln;
453 gp->scr_keyval = cl_keyval;
454 gp->scr_move = cl_move;
455 gp->scr_msg = NULL;
456 gp->scr_optchange = cl_optchange;
457 gp->scr_refresh = cl_refresh;
458 gp->scr_rename = cl_rename;
459 gp->scr_screen = cl_screen;
460 gp->scr_split = cl_split;
461 gp->scr_suspend = cl_suspend;
462 gp->scr_usage = cl_usage;
466 * perr --
467 * Print system error.
469 static void
470 perr(name, msg)
471 char *name, *msg;
473 (void)fprintf(stderr, "%s:", name);
474 if (msg != NULL)
475 (void)fprintf(stderr, "%s:", msg);
476 (void)fprintf(stderr, "%s\n", strerror(errno));
477 exit(1);