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