xref: /openbsd/usr.bin/mg/main.c (revision 17df1aa7)
1 /*	$OpenBSD: main.c,v 1.61 2009/06/04 02:23:37 kjell 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 
13 #ifndef NO_MACRO
14 #include "macro.h"
15 #endif	/* NO_MACRO */
16 
17 #include <err.h>
18 
19 int		 thisflag;			/* flags, this command	*/
20 int		 lastflag;			/* flags, last command	*/
21 int		 curgoal;			/* goal column		*/
22 int		 startrow;			/* row to start		*/
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(PF);
30 static __dead void usage(void);
31 
32 extern char	*__progname;
33 
34 static __dead void
35 usage()
36 {
37 	fprintf(stderr, "usage: %s [-n] [-f mode] [+number] [file ...]\n",
38 	    __progname);
39 	exit(1);
40 }
41 
42 int
43 main(int argc, char **argv)
44 {
45 	char	*cp, *init_fcn_name = NULL;
46 	PF	 init_fcn = NULL;
47 	int	 o, i, nfiles;
48 	int	 nobackups = 0;
49 	struct buffer *bp;
50 
51 	while ((o = getopt(argc, argv, "nf:")) != -1)
52 		switch (o) {
53 		case 'n':
54 			nobackups = 1;
55 			break;
56 		case 'f':
57 			if (init_fcn_name != NULL)
58 				errx(1, "cannot specify more than one "
59 				    "initial function");
60 			init_fcn_name = optarg;
61 			break;
62 		default:
63 			usage();
64 		}
65 	argc -= optind;
66 	argv += optind;
67 
68 	maps_init();		/* Keymaps and modes.		*/
69 	funmap_init();		/* Functions.			*/
70 
71 	/*
72 	 * This is where we initialize standalone extensions that should
73 	 * be loaded dynamically sometime in the future.
74 	 */
75 	{
76 		extern void grep_init(void);
77 		extern void theo_init(void);
78 		extern void cmode_init(void);
79 		extern void dired_init(void);
80 
81 		dired_init();
82 		grep_init();
83 		theo_init();
84 		cmode_init();
85 	}
86 
87 	if (init_fcn_name &&
88 	    (init_fcn = name_function(init_fcn_name)) == NULL)
89 		errx(1, "Unknown function `%s'", init_fcn_name);
90 
91 	vtinit();		/* Virtual terminal.		*/
92 	dirinit();		/* Get current directory.	*/
93 	edinit(init_fcn);	/* Buffers, windows.		*/
94 	ttykeymapinit();	/* Symbols, bindings.		*/
95 
96 	/*
97 	 * doing update() before reading files causes the error messages from
98 	 * the file I/O show up on the screen.	(and also an extra display of
99 	 * the mode line if there are files specified on the command line.)
100 	 */
101 	update();
102 
103 #ifndef NO_STARTUP
104 	/* user startup file */
105 	if ((cp = startupfile(NULL)) != NULL)
106 		(void)load(cp);
107 #endif	/* !NO_STARTUP */
108 
109 	/*
110 	 * Create scratch buffer now, killing old *init* buffer.
111 	 * This causes *scratch* to be created and made curbp,
112 	 * ensuring default modes are inherited from the startup
113 	 * file correctly
114 	 */
115 
116 	if ((bp = bfind("*init*", FALSE)) != NULL)
117 		killbuffer(bp);
118 
119 	/* Force FFOTHARG=1 so that this mode is enabled, not simply toggled */
120 	if (init_fcn)
121 		init_fcn(FFOTHARG, 1);
122 
123 	if (nobackups)
124 		makebkfile(FFARG, 0);
125 
126 	for (nfiles = 0, i = 0; i < argc; i++) {
127 		if (argv[i][0] == '+' && strlen(argv[i]) >= 2) {
128 			long long lval;
129 			const char *errstr;
130 
131 			lval = strtonum(&argv[i][1], INT_MIN, INT_MAX, &errstr);
132 			if (argv[i][1] == '\0' || errstr != NULL)
133 				goto notnum;
134 			startrow = lval;
135 		} else {
136 notnum:
137 			cp = adjustname(argv[i], FALSE);
138 			if (cp != NULL) {
139 				if (nfiles == 1)
140 					splitwind(0, 1);
141 
142 				if ((curbp = findbuffer(cp)) == NULL) {
143 					vttidy();
144 					errx(1, "Can't find current buffer!");
145 				}
146 				(void)showbuffer(curbp, curwp, 0);
147 				if (readin(cp) != TRUE)
148 					killbuffer(curbp);
149 				else {
150 					/* Ensure enabled, not just toggled */
151 					if (init_fcn_name)
152 						init_fcn(FFOTHARG, 1);
153 					nfiles++;
154 				}
155 			}
156 		}
157 	}
158 
159 	if (nfiles > 2)
160 		listbuffers(0, 1);
161 
162 	/* fake last flags */
163 	thisflag = 0;
164 	for (;;) {
165 		if (epresf == KCLEAR)
166 			eerase();
167 		if (epresf == TRUE)
168 			epresf = KCLEAR;
169 		if (winch_flag) {
170 			do_redraw(0, 0, TRUE);
171 			winch_flag = 0;
172 		}
173 		update();
174 		lastflag = thisflag;
175 		thisflag = 0;
176 
177 		switch (doin()) {
178 		case TRUE:
179 			break;
180 		case ABORT:
181 			ewprintf("Quit");
182 			/* FALLTHRU */
183 		case FALSE:
184 		default:
185 			ttbeep();
186 #ifndef NO_MACRO
187 			macrodef = FALSE;
188 #endif	/* !NO_MACRO */
189 		}
190 	}
191 }
192 
193 /*
194  * Initialize default buffer and window.
195  * Initially, buffer is named *init*. This is changed later
196  * to *scratch* after the startup files are read.
197  */
198 static void
199 edinit(PF init_fcn)
200 {
201 	struct buffer	*bp;
202 	struct mgwin	*wp;
203 
204 	bheadp = NULL;
205 	bp = bfind("*init*", TRUE);		/* Text buffer.		 */
206 	wp = new_window(bp);
207 	if (wp == NULL)
208 		panic("Out of memory");
209 	if (bp == NULL || wp == NULL)
210 		panic("edinit");
211 	curbp = bp;				/* Current ones.	 */
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 == FALSE
233 	    || eyesno("Modified buffers exist; really exit") == TRUE) {
234 		vttidy();
235 #ifdef SYSCLEANUP
236 		SYSCLEANUP;
237 #endif	/* SYSCLEANUP */
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