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