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