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