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