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