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:     char *erpath = EXSTRINGS;
  74:     register char *cp;
  75:     register int c;
  76:     bool recov = 0;
  77:     bool ivis;
  78:     bool itag = 0;
  79:     bool fast = 0;
  80: #ifdef TRACE
  81:     register char *tracef;
  82: #endif
  83: 
  84:     /*
  85: 	 * Immediately grab the tty modes so that we wont
  86: 	 * get messed up if an interrupt comes in quickly.
  87: 	 */
  88:     gTTY(1);
  89: #ifndef USG3TTY
  90:     normf = tty.sg_flags;
  91: #else
  92:     normf = tty;
  93: #endif
  94:     ppid = getpid();
  95: 
  96:     /*
  97: 	 * If a 'd' in our name, then set options for edit.
  98: 	 */
  99:     ivis = any('v', av[0]); /* vi */
 100: #ifdef RDONLY
 101:     if (any('w', av[0]))    /* view */
 102:         value(READONLY) = 1;
 103: #endif
 104:     if (any('d', av[0])) {  /* edit */
 105:         value(OPEN) = 0;
 106:         value(REPORT) = 1;
 107:         value(MAGIC) = 0;
 108:     }
 109: 
 110:     /*
 111: 	 * Open the error message file.
 112: 	 */
 113:     draino();
 114:     erfile = open(erpath, 0);
 115:     pstop();
 116: 
 117:     /*
 118: 	 * Initialize interrupt handling.
 119: 	 */
 120:     oldhup = signal(SIGHUP, SIG_IGN);
 121:     if (oldhup == SIG_DFL)
 122:         signal(SIGHUP, onhup);
 123:     oldquit = signal(SIGQUIT, SIG_IGN);
 124:     ruptible = signal(SIGINT, SIG_IGN) == SIG_DFL;
 125:     if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
 126:         signal(SIGTERM, onhup);
 127: 
 128:     /*
 129: 	 * Initialize end of core pointers.
 130: 	 * Normally we avoid breaking back to fendcore after each
 131: 	 * file since this can be expensive (much core-core copying).
 132: 	 * If your system can scatter load processes you could do
 133: 	 * this as ed does, saving a little core, but it will probably
 134: 	 * not often make much difference.
 135: 	 */
 136:     fendcore = (line *) sbrk(0);
 137:     endcore = fendcore - 2;
 138: 
 139:     /*
 140: 	 * Process flag arguments.
 141: 	 */
 142:     ac--, av++;
 143:     while (ac && av[0][0] == '-') {
 144:         c = av[0][1];
 145:         if (c == 0) {
 146:             hush = 1;
 147:             value(AUTOPRINT) = 0;
 148:             fast++;
 149:         } else switch (c) {
 150: 
 151: #ifdef TRACE
 152:         case 'T':
 153:             if (av[0][2] == 0)
 154:                 tracef = "trace";
 155:             else {
 156:                 tracef = tttrace;
 157:                 tracef[8] = av[0][2];
 158:                 if (tracef[8])
 159:                     tracef[9] = av[0][3];
 160:                 else
 161:                     tracef[9] = 0;
 162:             }
 163:             trace = fopen(tracef, "w");
 164:             if (trace == NULL)
 165:                 printf("Trace create error\n");
 166:             setbuf(trace, tracbuf);
 167:             break;
 168: 
 169: #endif
 170: 
 171: #ifdef RDONLY
 172:         case 'R':
 173:             value(READONLY) = 1;
 174:             break;
 175: #endif
 176: 
 177: #ifdef LISPCODE
 178:         case 'l':
 179:             value(LISP) = 1;
 180:             value(SHOWMATCH) = 1;
 181:             break;
 182: #endif
 183: 
 184:         case 'r':
 185:             recov++;
 186:             break;
 187: 
 188: #ifdef TAGSCODE
 189:         case 't':
 190:             if (ac > 1 && av[1][0] != '-') {
 191:                 ac--, av++;
 192:                 itag = 1;
 193:                 /* BUG: should check for too long tag. */
 194:                 CP(lasttag, av[0]);
 195:             }
 196:             break;
 197: #endif
 198: 
 199:         case 'v':
 200:             ivis = 1;
 201:             break;
 202: 
 203:         default:
 204:             smerror("Unknown option %s\n", av[0]);
 205:             break;
 206:         }
 207:         ac--, av++;
 208:     }
 209:     if (ac && av[0][0] == '+') {
 210:         firstpat = &av[0][1];
 211:         ac--, av++;
 212:     }
 213: 
 214:     /*
 215: 	 * If we are doing a recover and no filename
 216: 	 * was given, then execute an exrecover command with
 217: 	 * the -r option to type out the list of saved file names.
 218: 	 * Otherwise set the remembered file name to the first argument
 219: 	 * file name so the "recover" initial command will find it.
 220: 	 */
 221:     if (recov) {
 222:         if (ac == 0) {
 223:             ppid = 0;
 224:             setrupt();
 225:             execl(EXRECOVER, "exrecover", "-r", 0);
 226:             filioerr(EXRECOVER);
 227:             exit(1);
 228:         }
 229:         CP(savedfile, *av++), ac--;
 230:     }
 231: 
 232:     /*
 233: 	 * Initialize the argument list.
 234: 	 */
 235:     argv0 = av;
 236:     argc0 = ac;
 237:     args0 = av[0];
 238:     erewind();
 239: 
 240:     /*
 241: 	 * Initialize a temporary file (buffer) and
 242: 	 * set up terminal environment.  Read user startup commands.
 243: 	 */
 244:     init();
 245:     if (setexit() == 0) {
 246:         setrupt();
 247:         intty = isatty(0);
 248:         value(PROMPT) = intty;
 249:         if (cp = getenv("SHELL"))
 250:             CP(shell, cp);
 251:         if (fast || !intty)
 252:             setterm("dumb");
 253:         else {
 254:             gettmode();
 255:             if ((cp = getenv("TERM")) != 0 && *cp)
 256:                 setterm(cp);
 257:         }
 258:     }
 259:     if (setexit() == 0 && !fast && intty)
 260:         if ((globp = getenv("EXINIT")) && *globp)
 261:             commands(1, 1);
 262:         else if ((cp = getenv("HOME")) != 0 && *cp)
 263:             source(strcat(strcpy(genbuf, cp), "/.exrc"), 1);
 264: 
 265:     /*
 266: 	 * Initial processing.  Handle tag, recover, and file argument
 267: 	 * implied next commands.  If going in as 'vi', then don't do
 268: 	 * anything, just set initev so we will do it later (from within
 269: 	 * visual).
 270: 	 */
 271:     if (setexit() == 0) {
 272:         if (recov)
 273:             globp = "recover";
 274:         else if (itag)
 275:             globp = ivis ? "tag" : "tag|p";
 276:         else if (argc)
 277:             globp = "next";
 278:         if (ivis)
 279:             initev = globp;
 280:         else if (globp) {
 281:             inglobal = 1;
 282:             commands(1, 1);
 283:             inglobal = 0;
 284:         }
 285:     }
 286: 
 287:     /*
 288: 	 * Vi command... go into visual.
 289: 	 * Strange... everything in vi usually happens
 290: 	 * before we ever "start".
 291: 	 */
 292:     if (ivis) {
 293:         /*
 294: 		 * Don't have to be upward compatible with stupidity
 295: 		 * of starting editing at line $.
 296: 		 */
 297:         if (dol > zero)
 298:             dot = one;
 299:         globp = "visual";
 300:         if (setexit() == 0)
 301:             commands(1, 1);
 302:     }
 303: 
 304:     /*
 305: 	 * Clear out trash in state accumulated by startup,
 306: 	 * and then do the main command loop for a normal edit.
 307: 	 * If you quit out of a 'vi' command by doing Q or ^\,
 308: 	 * you also fall through to here.
 309: 	 */
 310:     ungetchar(0);
 311:     globp = 0;
 312:     initev = 0;
 313:     setlastchar('\n');
 314:     setexit();
 315:     commands(0, 0);
 316:     cleanup(1);
 317:     exit(0);
 318: }
 319: 
 320: /*
 321:  * Initialization, before editing a new file.
 322:  * Main thing here is to get a new buffer (in fileinit),
 323:  * rest is peripheral state resetting.
 324:  */
 325: init()
 326: {
 327:     register int i;
 328: 
 329:     fileinit();
 330:     dot = zero = truedol = unddol = dol = fendcore;
 331:     one = zero+1;
 332:     undkind = UNDNONE;
 333:     chng = 0;
 334:     edited = 0;
 335: #ifdef USG
 336:     signal (SIGHUP, SIG_IGN);
 337: #endif
 338: #ifdef USG3TTY
 339: # ifndef USG
 340:     signal (SIGHUP, SIG_IGN);
 341: # endif
 342: #endif
 343:     for (i = 0; i <= 'z'-'a'+1; i++)
 344:         names[i] = 1;
 345:     anymarks = 0;
 346: }
 347: 
 348: /*
 349:  * When a hangup occurs our actions are similar to a preserve
 350:  * command.  If the buffer has not been [Modified], then we do
 351:  * nothing but remove the temporary files and exit.
 352:  * Otherwise, we sync the temp file and then attempt a preserve.
 353:  * If the preserve succeeds, we unlink our temp files.
 354:  * If the preserve fails, we leave the temp files as they are
 355:  * as they are a backup even without preservation if they
 356:  * are not removed.
 357:  */
 358: onhup()
 359: {
 360: 
 361: #ifdef USG
 362:     /*
 363: 	 * USG tty driver can send multiple HUP's!!!
 364: 	 */
 365:     signal (SIGINT, SIG_IGN);
 366:     signal (SIGHUP, SIG_IGN);
 367: #endif
 368:     if (chng == 0) {
 369:         cleanup(1);
 370:         exit(0);
 371:     }
 372:     if (setexit() == 0) {
 373:         if (preserve()) {
 374:             cleanup(1);
 375:             exit(0);
 376:         }
 377:     }
 378:     exit(1);
 379: }
 380: 
 381: /*
 382:  * An interrupt occurred.  Drain any output which
 383:  * is still in the output buffering pipeline.
 384:  * Catch interrupts again.  Unless we are in visual
 385:  * reset the output state (out of -nl mode, e.g).
 386:  * Then like a normal error (with the \n before Interrupt
 387:  * suppressed in visual mode).
 388:  */
 389: onintr()
 390: {
 391: 
 392: #ifndef CBREAK
 393:     signal(SIGINT, onintr);
 394: #else
 395:     signal(SIGINT, inopen ? vintr : onintr);
 396: #endif
 397:     draino();
 398:     if (!inopen) {
 399:         pstop();
 400:         setlastchar('\n');
 401: #ifdef CBREAK
 402:     }
 403: #else
 404:     } else
 405:         vraw();
 406: #endif
 407:     error("\nInterrupt" + inopen);
 408: }
 409: 
 410: /*
 411:  * If we are interruptible, enable interrupts again.
 412:  * In some critical sections we turn interrupts off,
 413:  * but not very often.
 414:  */
 415: setrupt()
 416: {
 417: 
 418:     if (ruptible)
 419: #ifndef CBREAK
 420:         signal(SIGINT, onintr);
 421: #else
 422:         signal(SIGINT, inopen ? vintr : onintr);
 423: #endif
 424: }
 425: 
 426: preserve()
 427: {
 428: 
 429:     synctmp();
 430:     pid = fork();
 431:     if (pid < 0)
 432:         return (0);
 433:     if (pid == 0) {
 434:         close(0);
 435:         dup(tfile);
 436:         execl(EXPRESERVE, "expreserve", (char *) 0);
 437:         exit(1);
 438:     }
 439:     waitfor();
 440:     if (rpid == pid && status == 0)
 441:         return (1);
 442:     return (0);
 443: }
 444: 
 445: #ifndef V6
 446: exit(i)
 447:     int i;
 448: {
 449: #ifdef TRACE
 450:     if (trace)
 451:         fclose(trace);
 452: #endif
 453: 
 454:     _exit(i);
 455: }
 456: #endif
 457: 
 458: #ifdef ROOMTOBURN
 459: /*
 460:  * Return last component of unix path name p.
 461:  */
 462: char *
 463: tailpath(p)
 464: register char *p;
 465: {
 466:     register char *r;
 467: 
 468:     for (r=p; *p; p++)
 469:         if (*p == '/')
 470:             r = p+1;
 471:     return(r);
 472: }
 473: #endif

Defined functions

init defined in line 325; used 3 times
main defined in line 69; never used
onhup defined in line 358; used 4 times
onintr defined in line 389; used 7 times
preserve defined in line 426; used 2 times
setrupt defined in line 415; used 9 times
tailpath defined in line 462; used 1 times

Defined variables

tttrace defined in line 8; used 1 times
Last modified: 1980-09-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1167
Valid CSS Valid XHTML 1.0 Strict