-
Notifications
You must be signed in to change notification settings - Fork 26
/
main.c
352 lines (306 loc) · 7.22 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/* $OpenBSD: main.c,v 1.96 2023/10/24 10:26:02 op Exp $ */
/* This file is in the public domain. */
/*
* Mainline.
*/
#include <sys/queue.h>
#include <err.h>
#include <limits.h>
#include <locale.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#if HAVE_PTY_H
#include <pty.h>
#include <utmp.h>
#elif HAVE_UTIL_H
#include <util.h>
#endif
#include "def.h"
#include "kbd.h"
#include "funmap.h"
#include "macro.h"
#ifdef MGLOG
#include "log.h"
#endif
int thisflag; /* flags, this command */
int lastflag; /* flags, last command */
int curgoal; /* goal column */
int startrow; /* row to start */
int doaudiblebell; /* audible bell toggle */
int dovisiblebell; /* visible bell toggle */
int dblspace; /* sentence end #spaces */
int allbro; /* all buffs read-only */
int batch; /* for regress tests */
struct buffer *curbp; /* current buffer */
struct buffer *bheadp; /* BUFFER list head */
struct mgwin *curwp; /* current window */
struct mgwin *wheadp; /* MGWIN listhead */
struct vhead varhead; /* Variable list head */
char pat[NPAT]; /* pattern */
#ifndef __dead
#define __dead __attribute__ ((__noreturn__))
#endif
static void edinit(struct buffer *);
static void pty_init(void);
static __dead void usage(void);
extern char *__progname;
extern void closetags(void);
static __dead void
usage(void)
{
fprintf(stderr, "usage: %s [-nR] [-b file] [-f mode] [-u file] "
"[+number] [file ...]\n",
__progname);
exit(1);
}
int
main(int argc, char **argv)
{
FILE *ffp;
char file[NFILEN];
char *cp, *conffile = NULL, *init_fcn_name = NULL;
char *batchfile = NULL;
PF init_fcn = NULL;
int o, i, nfiles;
int nobackups = 0;
struct buffer *bp = NULL;
#if defined(__OpenBSD__)
if (pledge("stdio rpath wpath cpath fattr chown getpw tty proc exec",
NULL) == -1)
err(1, "pledge");
#endif
while ((o = getopt(argc, argv, "nRb:f:u:")) != -1)
switch (o) {
case 'b':
batch = 1;
batchfile = optarg;
break;
case 'R':
allbro = 1;
break;
case 'n':
nobackups = 1;
break;
case 'f':
if (init_fcn_name != NULL)
errx(1, "cannot specify more than one "
"initial function");
init_fcn_name = optarg;
break;
case 'u':
conffile = optarg;
break;
default:
usage();
}
if (batch && (conffile != NULL)) {
fprintf(stderr, "%s: -b and -u are mutually exclusive.\n",
__progname);
exit(1);
}
if (batch) {
pty_init();
conffile = batchfile;
}
if ((ffp = startupfile(NULL, conffile, file, sizeof(file))) == NULL &&
conffile != NULL) {
fprintf(stderr, "%s: Problem with file: %s\n", __progname,
conffile);
exit(1);
}
argc -= optind;
argv += optind;
setlocale(LC_CTYPE, "");
maps_init(); /* Keymaps and modes. */
funmap_init(); /* Functions. */
#ifdef MGLOG
if (!mgloginit())
errx(1, "Unable to create logging environment.");
#endif
/*
* This is where we initialize standalone extensions that should
* be loaded dynamically sometime in the future.
*/
{
extern void grep_init(void);
extern void cmode_init(void);
extern void dired_init(void);
dired_init();
grep_init();
cmode_init();
}
if (init_fcn_name &&
(init_fcn = name_function(init_fcn_name)) == NULL)
errx(1, "Unknown function `%s'", init_fcn_name);
vtinit(); /* Virtual terminal. */
dirinit(); /* Get current directory. */
edinit(bp); /* Buffers, windows. */
ttykeymapinit(); /* Symbols, bindings. */
bellinit(); /* Audible and visible bell. */
dblspace = 1; /* two spaces for sentence end. */
/*
* doing update() before reading files causes the error messages from
* the file I/O show up on the screen. (and also an extra display of
* the mode line if there are files specified on the command line.)
*/
update(CMODE);
/* user startup file. */
if (ffp != NULL) {
(void)load(ffp, file);
ffclose(ffp, NULL);
}
if (batch) {
vttidy();
return (0);
}
/*
* Now ensure any default buffer modes from the startup file are
* given to any files opened when parsing the startup file.
* Note *scratch* will also be updated.
*/
for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
bp->b_flag = defb_flag;
for (i = 0; i <= defb_nmodes; i++) {
bp->b_modes[i] = defb_modes[i];
}
}
/* Force FFOTHARG=1 so that this mode is enabled, not simply toggled */
if (init_fcn)
init_fcn(FFOTHARG, 1);
if (nobackups)
makebkfile(FFARG, 0);
for (nfiles = 0, i = 0; i < argc; i++) {
if (argv[i][0] == '+' && strlen(argv[i]) >= 2) {
long long lval;
const char *errstr;
lval = strtonum(&argv[i][1], INT_MIN, INT_MAX, &errstr);
if (argv[i][1] == '\0' || errstr != NULL)
goto notnum;
startrow = lval;
} else {
notnum:
cp = adjustname(argv[i], FALSE);
if (cp != NULL) {
if (nfiles == 1)
splitwind(0, 1);
if (fisdir(cp) == TRUE) {
(void)do_dired(cp);
continue;
}
if ((curbp = findbuffer(cp)) == NULL) {
vttidy();
errx(1, "Can't find current buffer!");
}
(void)showbuffer(curbp, curwp, 0);
if (readin(cp) != TRUE)
killbuffer(curbp);
else {
/* Ensure enabled, not just toggled */
if (init_fcn_name)
init_fcn(FFOTHARG, 1);
nfiles++;
}
if (allbro)
curbp->b_flag |= BFREADONLY;
}
}
}
if (nfiles > 2)
listbuffers(0, 1);
/* fake last flags */
thisflag = 0;
for (;;) {
if (epresf == KCLEAR)
eerase();
if (epresf == TRUE)
epresf = KCLEAR;
if (winch_flag) {
do_redraw(0, 0, TRUE);
winch_flag = 0;
}
update(CMODE);
lastflag = thisflag;
thisflag = 0;
switch (doin()) {
case TRUE:
break;
case ABORT:
ewprintf("Quit");
/* FALLTHRU */
case FALSE:
default:
macrodef = FALSE;
}
}
}
/*
* Initialize default buffer and window. Default buffer is called *scratch*.
*/
static void
edinit(struct buffer *bp)
{
struct mgwin *wp;
bheadp = NULL;
bp = bfind("*scratch*", TRUE); /* Text buffer. */
if (bp == NULL)
panic("edinit");
wp = new_window(bp);
if (wp == NULL)
panic("edinit: Out of memory");
curbp = bp; /* Current buffer. */
wheadp = wp;
curwp = wp;
wp->w_wndp = NULL; /* Initialize window. */
wp->w_linep = wp->w_dotp = bp->b_headp;
wp->w_ntrows = nrow - 2; /* 2 = mode, echo. */
wp->w_rflag = WFMODE | WFFULL; /* Full. */
}
/*
* Create pty for batch mode.
*/
static void
pty_init(void)
{
struct winsize ws;
int master;
int slave;
memset(&ws, 0, sizeof(ws));
ws.ws_col = 80,
ws.ws_row = 24;
openpty(&master, &slave, NULL, NULL, &ws);
login_tty(slave);
return;
}
/*
* Quit command. If an argument, always quit. Otherwise confirm if a buffer
* has been changed and not written out. Normally bound to "C-x C-c".
*/
int
quit(int f, int n)
{
int s;
if ((s = anycb(FALSE)) == ABORT)
return (ABORT);
if (s == FIOERR || s == UERROR)
return (FALSE);
if (s == FALSE
|| eyesno("Modified buffers exist; really exit") == TRUE) {
vttidy();
closetags();
exit(0);
}
return (TRUE);
}
/*
* User abort. Should be called by any input routine that sees a C-g to abort
* whatever C-g is aborting these days. Currently does nothing.
*/
int
ctrlg(int f, int n)
{
return (ABORT);
}