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