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