GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../cl/cl_main.c Lines: 0 103 0.0 %
Date: 2017-11-07 Branches: 0 47 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: cl_main.c,v 1.33 2016/05/05 20:36:41 martijn Exp $	*/
2
3
/*-
4
 * Copyright (c) 1993, 1994
5
 *	The Regents of the University of California.  All rights reserved.
6
 * Copyright (c) 1993, 1994, 1995, 1996
7
 *	Keith Bostic.  All rights reserved.
8
 *
9
 * See the LICENSE file for redistribution information.
10
 */
11
12
#include "config.h"
13
14
#include <sys/types.h>
15
#include <sys/queue.h>
16
17
#include <bitstring.h>
18
#include <curses.h>
19
#include <err.h>
20
#include <errno.h>
21
#include <fcntl.h>
22
#include <paths.h>
23
#include <signal.h>
24
#include <stdio.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <term.h>
28
#include <termios.h>
29
#include <unistd.h>
30
31
#include "../common/common.h"
32
#include "cl.h"
33
34
GS *__global_list;				/* GLOBAL: List of screens. */
35
36
static void	   cl_func_std(GS *);
37
static CL_PRIVATE *cl_init(GS *);
38
static GS	  *gs_init(void);
39
static int	   setsig(int, struct sigaction *, void (*)(int));
40
static void	   sig_end(GS *);
41
static void	   term_init(char *);
42
43
/*
44
 * main --
45
 *	This is the main loop for the standalone curses editor.
46
 */
47
int
48
main(int argc, char *argv[])
49
{
50
	CL_PRIVATE *clp;
51
	GS *gp;
52
	size_t rows, cols;
53
	int rval;
54
	char *ttype;
55
56
	/* Create and initialize the global structure. */
57
	__global_list = gp = gs_init();
58
59
	/* Create and initialize the CL_PRIVATE structure. */
60
	clp = cl_init(gp);
61
62
	/*
63
	 * Initialize the terminal information.
64
	 *
65
	 * We have to know what terminal it is from the start, since we may
66
	 * have to use termcap/terminfo to find out how big the screen is.
67
	 */
68
	if ((ttype = getenv("TERM")) == NULL)
69
		ttype = "unknown";
70
	term_init(ttype);
71
72
	/* Add the terminal type to the global structure. */
73
	if ((OG_D_STR(gp, GO_TERM) =
74
	    OG_STR(gp, GO_TERM) = strdup(ttype)) == NULL)
75
		err(1, NULL);
76
77
	/* Figure out how big the screen is. */
78
	if (cl_ssize(NULL, 0, &rows, &cols, NULL))
79
		exit (1);
80
81
	/* Add the rows and columns to the global structure. */
82
	OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = rows;
83
	OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = cols;
84
85
	/* Ex wants stdout to be buffered. */
86
	(void)setvbuf(stdout, NULL, _IOFBF, 0);
87
88
	/* Start catching signals. */
89
	if (sig_init(gp, NULL))
90
		exit (1);
91
92
	/* Run ex/vi. */
93
	rval = editor(gp, argc, argv);
94
95
	/* Clean up signals. */
96
	sig_end(gp);
97
98
	/* Clean up the terminal. */
99
	(void)cl_quit(gp);
100
101
	/*
102
	 * XXX
103
	 * Reset the O_MESG option.
104
	 */
105
	if (clp->tgw != TGW_UNKNOWN)
106
		(void)cl_omesg(NULL, clp, clp->tgw == TGW_SET);
107
108
	/*
109
	 * XXX
110
	 * Reset the X11 xterm icon/window name.
111
	 */
112
	if (F_ISSET(clp, CL_RENAME)) {
113
		(void)printf(XTERM_RENAME, ttype);
114
		(void)fflush(stdout);
115
	}
116
117
	/* If a killer signal arrived, pretend we just got it. */
118
	if (clp->killersig) {
119
		(void)signal(clp->killersig, SIG_DFL);
120
		(void)kill(getpid(), clp->killersig);
121
		/* NOTREACHED */
122
	}
123
124
	/* Free the global and CL private areas. */
125
#if defined(DEBUG) || defined(PURIFY)
126
	free(clp);
127
	free(gp);
128
#endif
129
130
	exit (rval);
131
}
132
133
/*
134
 * gs_init --
135
 *	Create and partially initialize the GS structure.
136
 */
137
static GS *
138
gs_init(void)
139
{
140
	GS *gp;
141
142
	/* Allocate the global structure. */
143
	if ((gp = calloc(1, sizeof(GS))) == NULL)
144
		err(1, NULL);
145
146
	return (gp);
147
}
148
149
/*
150
 * cl_init --
151
 *	Create and partially initialize the CL structure.
152
 */
153
static CL_PRIVATE *
154
cl_init(GS *gp)
155
{
156
	CL_PRIVATE *clp;
157
	int fd;
158
159
	/* Allocate the CL private structure. */
160
	if ((clp = calloc(1, sizeof(CL_PRIVATE))) == NULL)
161
		err(1, NULL);
162
	gp->cl_private = clp;
163
164
	/*
165
	 * Set the CL_STDIN_TTY flag.  It's purpose is to avoid setting
166
	 * and resetting the tty if the input isn't from there.  We also
167
	 * use the same test to determine if we're running a script or
168
	 * not.
169
	 */
170
	if (isatty(STDIN_FILENO))
171
		F_SET(clp, CL_STDIN_TTY);
172
	else
173
		F_SET(gp, G_SCRIPTED);
174
175
	/*
176
	 * We expect that if we've lost our controlling terminal that the
177
	 * open() (but not the tcgetattr()) will fail.
178
	 */
179
	if (F_ISSET(clp, CL_STDIN_TTY)) {
180
		if (tcgetattr(STDIN_FILENO, &clp->orig) == -1)
181
			goto tcfail;
182
	} else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) {
183
		if (tcgetattr(fd, &clp->orig) == -1)
184
tcfail:			err(1, "tcgetattr");
185
		(void)close(fd);
186
	}
187
188
	/* Initialize the list of curses functions. */
189
	cl_func_std(gp);
190
191
	return (clp);
192
}
193
194
/*
195
 * term_init --
196
 *	Initialize terminal information.
197
 */
198
static void
199
term_init(char *ttype)
200
{
201
	int err;
202
203
	/* Set up the terminal database information. */
204
	setupterm(ttype, STDOUT_FILENO, &err);
205
	switch (err) {
206
	case -1:
207
		errx(1, "No terminal database found");
208
	case 0:
209
		errx(1, "%s: unknown terminal type", ttype);
210
	}
211
}
212
213
#define	GLOBAL_CLP \
214
	CL_PRIVATE *clp = GCLP(__global_list);
215
static void
216
h_hup(int signo)
217
{
218
	GLOBAL_CLP;
219
220
	F_SET(clp, CL_SIGHUP);
221
	clp->killersig = SIGHUP;
222
}
223
224
static void
225
h_int(int signo)
226
{
227
	GLOBAL_CLP;
228
229
	F_SET(clp, CL_SIGINT);
230
}
231
232
static void
233
h_term(int signo)
234
{
235
	GLOBAL_CLP;
236
237
	F_SET(clp, CL_SIGTERM);
238
	clp->killersig = SIGTERM;
239
}
240
241
static void
242
h_winch(int signo)
243
{
244
	GLOBAL_CLP;
245
246
	F_SET(clp, CL_SIGWINCH);
247
}
248
#undef	GLOBAL_CLP
249
250
/*
251
 * sig_init --
252
 *	Initialize signals.
253
 *
254
 * PUBLIC: int sig_init(GS *, SCR *);
255
 */
256
int
257
sig_init(GS *gp, SCR *sp)
258
{
259
	CL_PRIVATE *clp;
260
261
	clp = GCLP(gp);
262
263
	if (sp == NULL) {
264
		if (setsig(SIGHUP, &clp->oact[INDX_HUP], h_hup) ||
265
		    setsig(SIGINT, &clp->oact[INDX_INT], h_int) ||
266
		    setsig(SIGTERM, &clp->oact[INDX_TERM], h_term) ||
267
		    setsig(SIGWINCH, &clp->oact[INDX_WINCH], h_winch)
268
		    )
269
			err(1, NULL);
270
	} else
271
		if (setsig(SIGHUP, NULL, h_hup) ||
272
		    setsig(SIGINT, NULL, h_int) ||
273
		    setsig(SIGTERM, NULL, h_term) ||
274
		    setsig(SIGWINCH, NULL, h_winch)
275
		    ) {
276
			msgq(sp, M_SYSERR, "signal-reset");
277
		}
278
	return (0);
279
}
280
281
/*
282
 * setsig --
283
 *	Set a signal handler.
284
 */
285
static int
286
setsig(int signo, struct sigaction *oactp, void (*handler)(int))
287
{
288
	struct sigaction act;
289
290
	/*
291
	 * Use sigaction(2), not signal(3), since we don't always want to
292
	 * restart system calls.  The example is when waiting for a command
293
	 * mode keystroke and SIGWINCH arrives.  Besides, you can't portably
294
	 * restart system calls (thanks, POSIX!).
295
	 */
296
	act.sa_handler = handler;
297
	sigemptyset(&act.sa_mask);
298
299
	act.sa_flags = 0;
300
	return (sigaction(signo, &act, oactp));
301
}
302
303
/*
304
 * sig_end --
305
 *	End signal setup.
306
 */
307
static void
308
sig_end(GS *gp)
309
{
310
	CL_PRIVATE *clp;
311
312
	clp = GCLP(gp);
313
	(void)sigaction(SIGHUP, NULL, &clp->oact[INDX_HUP]);
314
	(void)sigaction(SIGINT, NULL, &clp->oact[INDX_INT]);
315
	(void)sigaction(SIGTERM, NULL, &clp->oact[INDX_TERM]);
316
	(void)sigaction(SIGWINCH, NULL, &clp->oact[INDX_WINCH]);
317
}
318
319
/*
320
 * cl_func_std --
321
 *	Initialize the standard curses functions.
322
 */
323
static void
324
cl_func_std(GS *gp)
325
{
326
	gp->scr_addstr = cl_addstr;
327
	gp->scr_attr = cl_attr;
328
	gp->scr_baud = cl_baud;
329
	gp->scr_bell = cl_bell;
330
	gp->scr_busy = NULL;
331
	gp->scr_clrtoeol = cl_clrtoeol;
332
	gp->scr_cursor = cl_cursor;
333
	gp->scr_deleteln = cl_deleteln;
334
	gp->scr_event = cl_event;
335
	gp->scr_ex_adjust = cl_ex_adjust;
336
	gp->scr_fmap = cl_fmap;
337
	gp->scr_insertln = cl_insertln;
338
	gp->scr_keyval = cl_keyval;
339
	gp->scr_move = cl_move;
340
	gp->scr_msg = NULL;
341
	gp->scr_optchange = cl_optchange;
342
	gp->scr_refresh = cl_refresh;
343
	gp->scr_rename = cl_rename;
344
	gp->scr_screen = cl_screen;
345
	gp->scr_suspend = cl_suspend;
346
	gp->scr_usage = cl_usage;
347
}