1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char *sccsid = "@(#)ex.c 6.4 11/08/80"; 3 #include "ex.h" 4 #include "ex_argv.h" 5 #include "ex_temp.h" 6 #include "ex_tty.h" 7 8 #ifdef TRACE 9 char tttrace[] = { '/','d','e','v','/','t','t','y','x','x',0 }; 10 #endif 11 12 /* 13 * The code for ex is divided as follows: 14 * 15 * ex.c Entry point and routines handling interrupt, hangup 16 * signals; initialization code. 17 * 18 * ex_addr.c Address parsing routines for command mode decoding. 19 * Routines to set and check address ranges on commands. 20 * 21 * ex_cmds.c Command mode command decoding. 22 * 23 * ex_cmds2.c Subroutines for command decoding and processing of 24 * file names in the argument list. Routines to print 25 * messages and reset state when errors occur. 26 * 27 * ex_cmdsub.c Subroutines which implement command mode functions 28 * such as append, delete, join. 29 * 30 * ex_data.c Initialization of options. 31 * 32 * ex_get.c Command mode input routines. 33 * 34 * ex_io.c General input/output processing: file i/o, unix 35 * escapes, filtering, source commands, preserving 36 * and recovering. 37 * 38 * ex_put.c Terminal driving and optimizing routines for low-level 39 * output (cursor-positioning); output line formatting 40 * routines. 41 * 42 * ex_re.c Global commands, substitute, regular expression 43 * compilation and execution. 44 * 45 * ex_set.c The set command. 46 * 47 * ex_subr.c Loads of miscellaneous subroutines. 48 * 49 * ex_temp.c Editor buffer routines for main buffer and also 50 * for named buffers (Q registers if you will.) 51 * 52 * ex_tty.c Terminal dependent initializations from termcap 53 * data base, grabbing of tty modes (at beginning 54 * and after escapes). 55 * 56 * ex_unix.c Routines for the ! command and its variations. 57 * 58 * ex_v*.c Visual/open mode routines... see ex_v.c for a 59 * guide to the overall organization. 60 */ 61 62 /* 63 * Main procedure. Process arguments and then 64 * transfer control to the main command processing loop 65 * in the routine commands. We are entered as either "ex", "edit", "vi" 66 * or "view" and the distinction is made here. Actually, we are "vi" if 67 * there is a 'v' in our name, "view" is there is a 'w', and "edit" if 68 * there is a 'd' in our name. For edit we just diddle options; 69 * for vi we actually force an early visual command. 70 */ 71 main(ac, av) 72 register int ac; 73 register char *av[]; 74 { 75 #ifndef VMUNIX 76 char *erpath = EXSTRINGS; 77 #endif 78 register char *cp; 79 register int c; 80 bool recov = 0; 81 bool ivis; 82 bool itag = 0; 83 bool fast = 0; 84 extern int onemt(); 85 #ifdef TRACE 86 register char *tracef; 87 #endif 88 89 /* 90 * Immediately grab the tty modes so that we wont 91 * get messed up if an interrupt comes in quickly. 92 */ 93 gTTY(1); 94 #ifndef USG3TTY 95 normf = tty.sg_flags; 96 #else 97 normf = tty; 98 #endif 99 ppid = getpid(); 100 /* 101 * Defend against d's, v's, w's, and a's in directories of 102 * path leading to our true name. 103 */ 104 av[0] = tailpath(av[0]); 105 106 /* 107 * Figure out how we were invoked: ex, edit, vi, view. 108 */ 109 ivis = any('v', av[0]); /* "vi" */ 110 if (any('w', av[0])) /* "view" */ 111 value(READONLY) = 1; 112 if (any('d', av[0])) { /* "edit" */ 113 value(OPEN) = 0; 114 value(REPORT) = 1; 115 value(MAGIC) = 0; 116 } 117 118 #ifndef VMUNIX 119 /* 120 * For debugging take files out of . if name is a.out. 121 */ 122 if (av[0][0] == 'a') 123 erpath = tailpath(erpath); 124 #endif 125 /* 126 * Open the error message file. 127 */ 128 draino(); 129 #ifndef VMUNIX 130 erfile = open(erpath+4, 0); 131 if (erfile < 0) { 132 erfile = open(erpath, 0); 133 } 134 #endif 135 pstop(); 136 137 /* 138 * Initialize interrupt handling. 139 */ 140 oldhup = signal(SIGHUP, SIG_IGN); 141 if (oldhup == SIG_DFL) 142 signal(SIGHUP, onhup); 143 oldquit = signal(SIGQUIT, SIG_IGN); 144 ruptible = signal(SIGINT, SIG_IGN) == SIG_DFL; 145 if (signal(SIGTERM, SIG_IGN) == SIG_DFL) 146 signal(SIGTERM, onhup); 147 if (signal(SIGEMT, SIG_IGN) == SIG_DFL) 148 signal(SIGEMT, onemt); 149 150 /* 151 * Initialize end of core pointers. 152 * Normally we avoid breaking back to fendcore after each 153 * file since this can be expensive (much core-core copying). 154 * If your system can scatter load processes you could do 155 * this as ed does, saving a little core, but it will probably 156 * not often make much difference. 157 */ 158 fendcore = (line *) sbrk(0); 159 endcore = fendcore - 2; 160 161 /* 162 * Process flag arguments. 163 */ 164 ac--, av++; 165 while (ac && av[0][0] == '-') { 166 c = av[0][1]; 167 if (c == 0) { 168 hush = 1; 169 value(AUTOPRINT) = 0; 170 fast++; 171 } else switch (c) { 172 173 case 'R': 174 value(READONLY) = 1; 175 break; 176 177 #ifdef TRACE 178 case 'T': 179 if (av[0][2] == 0) 180 tracef = "trace"; 181 else { 182 tracef = tttrace; 183 tracef[8] = av[0][2]; 184 if (tracef[8]) 185 tracef[9] = av[0][3]; 186 else 187 tracef[9] = 0; 188 } 189 trace = fopen(tracef, "w"); 190 if (trace == NULL) 191 printf("Trace create error\n"); 192 setbuf(trace, tracbuf); 193 break; 194 195 #endif 196 197 #ifdef LISPCODE 198 case 'l': 199 value(LISP) = 1; 200 value(SHOWMATCH) = 1; 201 break; 202 #endif 203 204 case 'r': 205 recov++; 206 break; 207 208 case 't': 209 if (ac > 1 && av[1][0] != '-') { 210 ac--, av++; 211 itag = 1; 212 /* BUG: should check for too long tag. */ 213 CP(lasttag, av[0]); 214 } 215 break; 216 217 case 'v': 218 ivis = 1; 219 break; 220 221 case 'w': 222 defwind = 0; 223 if (av[0][2] == 0) defwind = 3; 224 else for (cp = &av[0][2]; isdigit(*cp); cp++) 225 defwind = 10*defwind + *cp - '0'; 226 break; 227 228 #ifdef CRYPT 229 case 'x': 230 /* -x: encrypted mode */ 231 xflag = 1; 232 break; 233 #endif 234 235 default: 236 smerror("Unknown option %s\n", av[0]); 237 break; 238 } 239 ac--, av++; 240 } 241 242 #ifdef SIGTSTP 243 if (!hush && signal(SIGTSTP, SIG_IGN) == SIG_DFL) 244 signal(SIGTSTP, onsusp), dosusp++; 245 #endif 246 247 if (ac && av[0][0] == '+') { 248 firstpat = &av[0][1]; 249 ac--, av++; 250 } 251 252 #ifdef CRYPT 253 if(xflag){ 254 key = getpass(KEYPROMPT); 255 kflag = crinit(key, perm); 256 } 257 #endif 258 259 /* 260 * If we are doing a recover and no filename 261 * was given, then execute an exrecover command with 262 * the -r option to type out the list of saved file names. 263 * Otherwise set the remembered file name to the first argument 264 * file name so the "recover" initial command will find it. 265 */ 266 if (recov) { 267 if (ac == 0) { 268 ppid = 0; 269 setrupt(); 270 execl(EXRECOVER, "exrecover", "-r", 0); 271 filioerr(EXRECOVER); 272 exit(1); 273 } 274 CP(savedfile, *av++), ac--; 275 } 276 277 /* 278 * Initialize the argument list. 279 */ 280 argv0 = av; 281 argc0 = ac; 282 args0 = av[0]; 283 erewind(); 284 285 /* 286 * Initialize a temporary file (buffer) and 287 * set up terminal environment. Read user startup commands. 288 */ 289 if (setexit() == 0) { 290 setrupt(); 291 intty = isatty(0); 292 value(PROMPT) = intty; 293 if (cp = getenv("SHELL")) 294 CP(shell, cp); 295 if (fast || !intty) 296 setterm("dumb"); 297 else { 298 gettmode(); 299 if ((cp = getenv("TERM")) != 0 && *cp) 300 setterm(cp); 301 } 302 } 303 if (setexit() == 0 && !fast && intty) 304 if ((globp = getenv("EXINIT")) && *globp) 305 commands(1,1); 306 else { 307 globp = 0; 308 if ((cp = getenv("HOME")) != 0 && *cp) 309 source(strcat(strcpy(genbuf, cp), "/.exrc"), 1); 310 } 311 init(); /* moved after prev 2 chunks to fix directory option */ 312 313 /* 314 * Initial processing. Handle tag, recover, and file argument 315 * implied next commands. If going in as 'vi', then don't do 316 * anything, just set initev so we will do it later (from within 317 * visual). 318 */ 319 if (setexit() == 0) { 320 if (recov) 321 globp = "recover"; 322 else if (itag) 323 globp = ivis ? "tag" : "tag|p"; 324 else if (argc) 325 globp = "next"; 326 if (ivis) 327 initev = globp; 328 else if (globp) { 329 inglobal = 1; 330 commands(1, 1); 331 inglobal = 0; 332 } 333 } 334 335 /* 336 * Vi command... go into visual. 337 * Strange... everything in vi usually happens 338 * before we ever "start". 339 */ 340 if (ivis) { 341 /* 342 * Don't have to be upward compatible with stupidity 343 * of starting editing at line $. 344 */ 345 if (dol > zero) 346 dot = one; 347 globp = "visual"; 348 if (setexit() == 0) 349 commands(1, 1); 350 } 351 352 /* 353 * Clear out trash in state accumulated by startup, 354 * and then do the main command loop for a normal edit. 355 * If you quit out of a 'vi' command by doing Q or ^\, 356 * you also fall through to here. 357 */ 358 seenprompt = 1; 359 ungetchar(0); 360 globp = 0; 361 initev = 0; 362 setlastchar('\n'); 363 setexit(); 364 commands(0, 0); 365 cleanup(1); 366 exit(0); 367 } 368 369 /* 370 * Initialization, before editing a new file. 371 * Main thing here is to get a new buffer (in fileinit), 372 * rest is peripheral state resetting. 373 */ 374 init() 375 { 376 register int i; 377 378 fileinit(); 379 dot = zero = truedol = unddol = dol = fendcore; 380 one = zero+1; 381 undkind = UNDNONE; 382 chng = 0; 383 edited = 0; 384 for (i = 0; i <= 'z'-'a'+1; i++) 385 names[i] = 1; 386 anymarks = 0; 387 #ifdef CRYPT 388 if(xflag) { 389 xtflag = 1; 390 makekey(key, tperm); 391 } 392 #endif 393 } 394 395 /* 396 * Return last component of unix path name p. 397 */ 398 char * 399 tailpath(p) 400 register char *p; 401 { 402 register char *r; 403 404 for (r=p; *p; p++) 405 if (*p == '/') 406 r = p+1; 407 return(r); 408 } 409