1 /* $OpenBSD: main.c,v 1.83 2016/07/14 08:31:18 semarie 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 theo_init(void); 96 extern void cmode_init(void); 97 extern void dired_init(void); 98 99 dired_init(); 100 grep_init(); 101 theo_init(); 102 cmode_init(); 103 } 104 105 if (init_fcn_name && 106 (init_fcn = name_function(init_fcn_name)) == NULL) 107 errx(1, "Unknown function `%s'", init_fcn_name); 108 109 vtinit(); /* Virtual terminal. */ 110 dirinit(); /* Get current directory. */ 111 edinit(bp); /* Buffers, windows. */ 112 ttykeymapinit(); /* Symbols, bindings. */ 113 bellinit(); /* Audible and visible bell. */ 114 dblspace = 1; /* two spaces for sentence end. */ 115 116 /* 117 * doing update() before reading files causes the error messages from 118 * the file I/O show up on the screen. (and also an extra display of 119 * the mode line if there are files specified on the command line.) 120 */ 121 update(CMODE); 122 123 /* user startup file. */ 124 if ((cp = startupfile(NULL)) != NULL) 125 (void)load(cp); 126 127 /* 128 * Now ensure any default buffer modes from the startup file are 129 * given to any files opened when parsing the startup file. 130 * Note *scratch* will also be updated. 131 */ 132 for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { 133 bp->b_flag = defb_flag; 134 for (i = 0; i <= defb_nmodes; i++) { 135 bp->b_modes[i] = defb_modes[i]; 136 } 137 } 138 139 /* Force FFOTHARG=1 so that this mode is enabled, not simply toggled */ 140 if (init_fcn) 141 init_fcn(FFOTHARG, 1); 142 143 if (nobackups) 144 makebkfile(FFARG, 0); 145 146 for (nfiles = 0, i = 0; i < argc; i++) { 147 if (argv[i][0] == '+' && strlen(argv[i]) >= 2) { 148 long long lval; 149 const char *errstr; 150 151 lval = strtonum(&argv[i][1], INT_MIN, INT_MAX, &errstr); 152 if (argv[i][1] == '\0' || errstr != NULL) 153 goto notnum; 154 startrow = lval; 155 } else { 156 notnum: 157 cp = adjustname(argv[i], FALSE); 158 if (cp != NULL) { 159 if (nfiles == 1) 160 splitwind(0, 1); 161 162 if (fisdir(cp) == TRUE) { 163 (void)do_dired(cp); 164 continue; 165 } 166 if ((curbp = findbuffer(cp)) == NULL) { 167 vttidy(); 168 errx(1, "Can't find current buffer!"); 169 } 170 (void)showbuffer(curbp, curwp, 0); 171 if (readin(cp) != TRUE) 172 killbuffer(curbp); 173 else { 174 /* Ensure enabled, not just toggled */ 175 if (init_fcn_name) 176 init_fcn(FFOTHARG, 1); 177 nfiles++; 178 } 179 if (bro) 180 curbp->b_flag |= BFREADONLY; 181 } 182 } 183 } 184 185 if (nfiles > 2) 186 listbuffers(0, 1); 187 188 /* fake last flags */ 189 thisflag = 0; 190 for (;;) { 191 if (epresf == KCLEAR) 192 eerase(); 193 if (epresf == TRUE) 194 epresf = KCLEAR; 195 if (winch_flag) { 196 do_redraw(0, 0, TRUE); 197 winch_flag = 0; 198 } 199 update(CMODE); 200 lastflag = thisflag; 201 thisflag = 0; 202 203 switch (doin()) { 204 case TRUE: 205 break; 206 case ABORT: 207 ewprintf("Quit"); 208 /* FALLTHRU */ 209 case FALSE: 210 default: 211 macrodef = FALSE; 212 } 213 } 214 } 215 216 /* 217 * Initialize default buffer and window. Default buffer is called *scratch*. 218 */ 219 static void 220 edinit(struct buffer *bp) 221 { 222 struct mgwin *wp; 223 224 bheadp = NULL; 225 bp = bfind("*scratch*", TRUE); /* Text buffer. */ 226 if (bp == NULL) 227 panic("edinit"); 228 229 wp = new_window(bp); 230 if (wp == NULL) 231 panic("edinit: Out of memory"); 232 233 curbp = bp; /* Current buffer. */ 234 wheadp = wp; 235 curwp = wp; 236 wp->w_wndp = NULL; /* Initialize window. */ 237 wp->w_linep = wp->w_dotp = bp->b_headp; 238 wp->w_ntrows = nrow - 2; /* 2 = mode, echo. */ 239 wp->w_rflag = WFMODE | WFFULL; /* Full. */ 240 } 241 242 /* 243 * Quit command. If an argument, always quit. Otherwise confirm if a buffer 244 * has been changed and not written out. Normally bound to "C-X C-C". 245 */ 246 /* ARGSUSED */ 247 int 248 quit(int f, int n) 249 { 250 int s; 251 252 if ((s = anycb(FALSE)) == ABORT) 253 return (ABORT); 254 if (s == FIOERR || s == UERROR) 255 return (FALSE); 256 if (s == FALSE 257 || eyesno("Modified buffers exist; really exit") == TRUE) { 258 vttidy(); 259 closetags(); 260 exit(0); 261 } 262 return (TRUE); 263 } 264 265 /* 266 * User abort. Should be called by any input routine that sees a C-g to abort 267 * whatever C-g is aborting these days. Currently does nothing. 268 */ 269 /* ARGSUSED */ 270 int 271 ctrlg(int f, int n) 272 { 273 return (ABORT); 274 } 275