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