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