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: }

Defined functions

init defined in line 402; used 3 times
iownit defined in line 442; used 2 times
main defined in line 85; never used
tailpath defined in line 426; used 3 times

Defined variables

copyright defined in line 8; never used
sccsid defined in line 14; never used
tttrace defined in line 23; used 1 times

Defined macros

tracbuf defined in line 193; used 1 times
Last modified: 1985-08-30
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1902
Valid CSS Valid XHTML 1.0 Strict