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