xref: /openbsd-src/usr.bin/mg/main.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: main.c,v 1.83 2016/07/14 08:31:18 semarie Exp $	*/
2 
3 /* This file is in the public domain. */
4 
5 /*
6  *	Mainline.
7  */
8 
9 #include <sys/queue.h>
10 #include <err.h>
11 #include <limits.h>
12 #include <locale.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 
19 #include "def.h"
20 #include "kbd.h"
21 #include "funmap.h"
22 #include "macro.h"
23 
24 int		 thisflag;			/* flags, this command	*/
25 int		 lastflag;			/* flags, last command	*/
26 int		 curgoal;			/* goal column		*/
27 int		 startrow;			/* row to start		*/
28 int		 doaudiblebell;			/* audible bell toggle	*/
29 int		 dovisiblebell;			/* visible bell toggle	*/
30 int		 dblspace;			/* sentence end #spaces	*/
31 struct buffer	*curbp;				/* current buffer	*/
32 struct buffer	*bheadp;			/* BUFFER list head	*/
33 struct mgwin	*curwp;				/* current window	*/
34 struct mgwin	*wheadp;			/* MGWIN listhead	*/
35 char		 pat[NPAT];			/* pattern		*/
36 
37 static void	 edinit(struct buffer *);
38 static __dead void usage(void);
39 
40 extern char	*__progname;
41 extern void     closetags(void);
42 
43 static __dead void
44 usage()
45 {
46 	fprintf(stderr, "usage: %s [-nR] [-f mode] [+number] [file ...]\n",
47 	    __progname);
48 	exit(1);
49 }
50 
51 int
52 main(int argc, char **argv)
53 {
54 	char		*cp, *init_fcn_name = NULL;
55 	PF		 init_fcn = NULL;
56 	int	 	 o, i, nfiles;
57 	int	  	 nobackups = 0, bro = 0;
58 	struct buffer	*bp = NULL;
59 
60 	if (pledge("stdio rpath wpath cpath fattr chown getpw tty proc exec",
61 	    NULL) == -1)
62 		err(1, "pledge");
63 
64 	while ((o = getopt(argc, argv, "nRf:")) != -1)
65 		switch (o) {
66 		case 'R':
67 			bro = 1;
68 			break;
69 		case 'n':
70 			nobackups = 1;
71 			break;
72 		case 'f':
73 			if (init_fcn_name != NULL)
74 				errx(1, "cannot specify more than one "
75 				    "initial function");
76 			init_fcn_name = optarg;
77 			break;
78 		default:
79 			usage();
80 		}
81 	argc -= optind;
82 	argv += optind;
83 
84 	setlocale(LC_CTYPE, "");
85 
86 	maps_init();		/* Keymaps and modes.		*/
87 	funmap_init();		/* Functions.			*/
88 
89 	/*
90 	 * This is where we initialize standalone extensions that should
91 	 * be loaded dynamically sometime in the future.
92 	 */
93 	{
94 		extern void grep_init(void);
95 		extern void theo_init(void);
96 		extern void cmode_init(void);
97 		extern void dired_init(void);
98 
99 		dired_init();
100 		grep_init();
101 		theo_init();
102 		cmode_init();
103 	}
104 
105 	if (init_fcn_name &&
106 	    (init_fcn = name_function(init_fcn_name)) == NULL)
107 		errx(1, "Unknown function `%s'", init_fcn_name);
108 
109 	vtinit();		/* Virtual terminal.		*/
110 	dirinit();		/* Get current directory.	*/
111 	edinit(bp);		/* Buffers, windows.		*/
112 	ttykeymapinit();	/* Symbols, bindings.		*/
113 	bellinit();		/* Audible and visible bell.	*/
114 	dblspace = 1;		/* two spaces for sentence end. */
115 
116 	/*
117 	 * doing update() before reading files causes the error messages from
118 	 * the file I/O show up on the screen.	(and also an extra display of
119 	 * the mode line if there are files specified on the command line.)
120 	 */
121 	update(CMODE);
122 
123 	/* user startup file. */
124 	if ((cp = startupfile(NULL)) != NULL)
125 		(void)load(cp);
126 
127 	/*
128 	 * Now ensure any default buffer modes from the startup file are
129 	 * given to any files opened when parsing the startup file.
130 	 * Note *scratch* will also be updated.
131 	 */
132 	for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
133 		bp->b_flag = defb_flag;
134 		for (i = 0; i <= defb_nmodes; i++) {
135                 	bp->b_modes[i] = defb_modes[i];
136         	}
137 	}
138 
139 	/* Force FFOTHARG=1 so that this mode is enabled, not simply toggled */
140 	if (init_fcn)
141 		init_fcn(FFOTHARG, 1);
142 
143 	if (nobackups)
144 		makebkfile(FFARG, 0);
145 
146 	for (nfiles = 0, i = 0; i < argc; i++) {
147 		if (argv[i][0] == '+' && strlen(argv[i]) >= 2) {
148 			long long lval;
149 			const char *errstr;
150 
151 			lval = strtonum(&argv[i][1], INT_MIN, INT_MAX, &errstr);
152 			if (argv[i][1] == '\0' || errstr != NULL)
153 				goto notnum;
154 			startrow = lval;
155 		} else {
156 notnum:
157 			cp = adjustname(argv[i], FALSE);
158 			if (cp != NULL) {
159 				if (nfiles == 1)
160 					splitwind(0, 1);
161 
162 				if (fisdir(cp) == TRUE) {
163 					(void)do_dired(cp);
164 					continue;
165 				}
166 				if ((curbp = findbuffer(cp)) == NULL) {
167 					vttidy();
168 					errx(1, "Can't find current buffer!");
169 				}
170 				(void)showbuffer(curbp, curwp, 0);
171 				if (readin(cp) != TRUE)
172 					killbuffer(curbp);
173 				else {
174 					/* Ensure enabled, not just toggled */
175 					if (init_fcn_name)
176 						init_fcn(FFOTHARG, 1);
177 					nfiles++;
178 				}
179 				if (bro)
180 					curbp->b_flag |= BFREADONLY;
181 			}
182 		}
183 	}
184 
185 	if (nfiles > 2)
186 		listbuffers(0, 1);
187 
188 	/* fake last flags */
189 	thisflag = 0;
190 	for (;;) {
191 		if (epresf == KCLEAR)
192 			eerase();
193 		if (epresf == TRUE)
194 			epresf = KCLEAR;
195 		if (winch_flag) {
196 			do_redraw(0, 0, TRUE);
197 			winch_flag = 0;
198 		}
199 		update(CMODE);
200 		lastflag = thisflag;
201 		thisflag = 0;
202 
203 		switch (doin()) {
204 		case TRUE:
205 			break;
206 		case ABORT:
207 			ewprintf("Quit");
208 			/* FALLTHRU */
209 		case FALSE:
210 		default:
211 			macrodef = FALSE;
212 		}
213 	}
214 }
215 
216 /*
217  * Initialize default buffer and window. Default buffer is called *scratch*.
218  */
219 static void
220 edinit(struct buffer *bp)
221 {
222 	struct mgwin	*wp;
223 
224 	bheadp = NULL;
225 	bp = bfind("*scratch*", TRUE);		/* Text buffer.          */
226 	if (bp == NULL)
227 		panic("edinit");
228 
229 	wp = new_window(bp);
230 	if (wp == NULL)
231 		panic("edinit: Out of memory");
232 
233 	curbp = bp;				/* Current buffer.	 */
234 	wheadp = wp;
235 	curwp = wp;
236 	wp->w_wndp = NULL;			/* Initialize window.	 */
237 	wp->w_linep = wp->w_dotp = bp->b_headp;
238 	wp->w_ntrows = nrow - 2;		/* 2 = mode, echo.	 */
239 	wp->w_rflag = WFMODE | WFFULL;		/* Full.		 */
240 }
241 
242 /*
243  * Quit command.  If an argument, always quit.  Otherwise confirm if a buffer
244  * has been changed and not written out.  Normally bound to "C-X C-C".
245  */
246 /* ARGSUSED */
247 int
248 quit(int f, int n)
249 {
250 	int	 s;
251 
252 	if ((s = anycb(FALSE)) == ABORT)
253 		return (ABORT);
254 	if (s == FIOERR || s == UERROR)
255 		return (FALSE);
256 	if (s == FALSE
257 	    || eyesno("Modified buffers exist; really exit") == TRUE) {
258 		vttidy();
259 		closetags();
260 		exit(0);
261 	}
262 	return (TRUE);
263 }
264 
265 /*
266  * User abort.  Should be called by any input routine that sees a C-g to abort
267  * whatever C-g is aborting these days. Currently does nothing.
268  */
269 /* ARGSUSED */
270 int
271 ctrlg(int f, int n)
272 {
273 	return (ABORT);
274 }
275