|
|
1.1 ! root 1: /* Copyright (c) 1980 Regents of the University of California */ ! 2: static char *sccsid = "%W% %G%"; ! 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: * When a hangup occurs our actions are similar to a preserve ! 397: * command. If the buffer has not been [Modified], then we do ! 398: * nothing but remove the temporary files and exit. ! 399: * Otherwise, we sync the temp file and then attempt a preserve. ! 400: * If the preserve succeeds, we unlink our temp files. ! 401: * If the preserve fails, we leave the temp files as they are ! 402: * as they are a backup even without preservation if they ! 403: * are not removed. ! 404: */ ! 405: onhup() ! 406: { ! 407: ! 408: /* ! 409: * USG tty driver can send multiple HUP's!! ! 410: */ ! 411: signal(SIGINT, SIG_IGN); ! 412: signal(SIGHUP, SIG_IGN); ! 413: if (chng == 0) { ! 414: cleanup(1); ! 415: exit(0); ! 416: } ! 417: if (setexit() == 0) { ! 418: if (preserve()) { ! 419: cleanup(1); ! 420: exit(0); ! 421: } ! 422: } ! 423: exit(1); ! 424: } ! 425: ! 426: /* ! 427: * An interrupt occurred. Drain any output which ! 428: * is still in the output buffering pipeline. ! 429: * Catch interrupts again. Unless we are in visual ! 430: * reset the output state (out of -nl mode, e.g). ! 431: * Then like a normal error (with the \n before Interrupt ! 432: * suppressed in visual mode). ! 433: */ ! 434: onintr() ! 435: { ! 436: ! 437: #ifndef CBREAK ! 438: signal(SIGINT, onintr); ! 439: #else ! 440: signal(SIGINT, inopen ? vintr : onintr); ! 441: #endif ! 442: draino(); ! 443: if (!inopen) { ! 444: pstop(); ! 445: setlastchar('\n'); ! 446: #ifdef CBREAK ! 447: } ! 448: #else ! 449: } else ! 450: vraw(); ! 451: #endif ! 452: error("\nInterrupt" + inopen); ! 453: } ! 454: ! 455: /* ! 456: * If we are interruptible, enable interrupts again. ! 457: * In some critical sections we turn interrupts off, ! 458: * but not very often. ! 459: */ ! 460: setrupt() ! 461: { ! 462: ! 463: if (ruptible) { ! 464: #ifndef CBREAK ! 465: signal(SIGINT, onintr); ! 466: #else ! 467: signal(SIGINT, inopen ? vintr : onintr); ! 468: #endif ! 469: #ifdef SIGTSTP ! 470: if (dosusp) ! 471: signal(SIGTSTP, onsusp); ! 472: #endif ! 473: } ! 474: } ! 475: ! 476: preserve() ! 477: { ! 478: ! 479: #ifdef VMUNIX ! 480: tflush(); ! 481: #endif ! 482: synctmp(); ! 483: pid = fork(); ! 484: if (pid < 0) ! 485: return (0); ! 486: if (pid == 0) { ! 487: close(0); ! 488: dup(tfile); ! 489: execl(EXPRESERVE, "expreserve", (char *) 0); ! 490: exit(1); ! 491: } ! 492: waitfor(); ! 493: if (rpid == pid && status == 0) ! 494: return (1); ! 495: return (0); ! 496: } ! 497: ! 498: #ifndef V6 ! 499: exit(i) ! 500: int i; ! 501: { ! 502: ! 503: # ifdef TRACE ! 504: if (trace) ! 505: fclose(trace); ! 506: # endif ! 507: _exit(i); ! 508: } ! 509: #endif ! 510: ! 511: /* ! 512: * Return last component of unix path name p. ! 513: */ ! 514: char * ! 515: tailpath(p) ! 516: register char *p; ! 517: { ! 518: register char *r; ! 519: ! 520: for (r=p; *p; p++) ! 521: if (*p == '/') ! 522: r = p+1; ! 523: return(r); ! 524: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.