# 3.3-3.4 ed - ex.c << '-*-END-*-' 418a #ifdef TIOCLGET if (dosusp) signal(SIGTSTP, onsusp); #endif } . 413c if (ruptible) { . 362a /* * USG tty driver can send multiple HUP's!! */ signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); . 347a if(xflag) { xtflag = 1; makekey(key, tperm); } . 344a #ifdef USG signal (SIGHUP, SIG_IGN); #endif #ifdef USG3TTY #ifndef USG signal (SIGHUP, SIG_IGN); #endif #endif . 272,273c else { globp = 0; if ((cp = getenv("HOME")) != 0 && *cp) source(strcat(strcpy(genbuf, cp), "/.exrc"), 1); } . 270c if ((globp = getenv("EXINIT")) && *globp) . 265c if ((cp = getenv("TERM")) != 0 && *cp) . 260a if (cp = getenv("SHELL")) CP(shell, cp); . 225a if(xflag){ key = getpass(KEYPROMPT); kflag = crinit(key, perm); } . 214a case 'x': /* -x: encrypted mode */ xflag = 1; break; . 163a case 'R': value(READONLY) = 1; break; . 139a #ifdef TIOCLGET if (signal(SIGTSTP, SIG_IGN) == SIG_DFL) signal(SIGTSTP, onsusp), dosusp++; #endif . 118a * For debugging take files out of . if name is a.out. */ if (av[0][0] == 'a') erpath = tailpath(erpath); #endif /* . 117a #ifndef VMUNIX . 104,112c ivis = any('v', av[0]); /* "vi" */ if (any('w', av[0])) /* "view" */ value(READONLY) = 1; if (any('d', av[0])) { /* "edit" */ . 101,102c * Figure out how we were invoked: ex, edit, vi, view. . 98d 94c * Defend against d's, v's, w's, and a's in directories of . 91a #else normf = tty; #endif . 90a #ifndef USG3TTY . 62,67c * in the routine commands. We are entered as either "ex", "edit", "vi" * or "view" and the distinction is made here. Actually, we are "vi" if * there is a 'v' in our name, "view" is there is a 'w', and "edit" if * there is a 'd' in our name. For edit we just diddle options; * for vi we actually force an early visual command. . 54a * ex_unix.c Routines for the ! command and its variations. * . w q '-*-END-*-' ed - ex.h << '-*-END-*-' 335a int onsusp(); . 279a * Various miscellaneous flags and buffers needed by the encryption routines. */ #define KSIZE 9 /* key size for encryption */ #define KEYPROMPT "Key: " int xflag; /* True if we are in encryption mode */ int xtflag; /* True if the temp file is being encrypted */ int kflag; /* True if the key has been accepted */ char perm[768]; char tperm[768]; char *key; char crbuf[CRSIZE]; char *getpass(); /* . 175a short oprompt; /* Saved during source */ . 156a bool inappend; /* in ex command append mode */ . 144a #ifdef TIOCLGET bool dosusp; /* Do SIGTSTP in visual when ^Z typed */ #endif . 50a /* * The following little dance copes with the new USG tty handling. * This stuff has the advantage of considerable flexibility, and * the disadvantage of being incompatible with anything else. * The presence of the symbol USG3TTY will indicate the new code: * in this case, we define CBREAK (because we can simulate it exactly), * but we won't actually use it, so we set it to a value that will * probably blow the compilation if we goof up. */ #ifdef USG3TTY #include #define CBREAK xxxxx #else #include #endif . 46d 39c * or to csvax.mark@berkeley on the ARPA-net. I would particularly like to hear . 32c * Mark Horton . 7c * Ex version 3 (see exact version in ex_cmds.c, search for /Version/) . w q '-*-END-*-' ed - ex_addr.c << '-*-END-*-' 204a if (loc1 == loc2) loc2++; . 197a } . 195c while (loc1 <= inline) { if (loc1 == loc2) loc2++; . w q '-*-END-*-' ed - ex_cmds.c << '-*-END-*-' 758a vmacchng(0); . 747c vclrech(1); /* vcontin(0); */ . 737a vmacchng(0); . 716a /* " */ case '"': comment(); continue; . 651a vmacchng(0); . 606a if (inopen) { c = 'e'; goto editcmd; } . 600c printf("Version 3.4, June 24, 1980"); . 579a /* unabbreviate */ case 'a': tail2of("unabbreviate"); setnoaddr(); mapcmd(1, 1); anyabbrs = 1; continue; . 578c mapcmd(1, 0); . 575c switch(peekchar()) { /* unmap */ case 'm': . 573d 567a vmacchng(0); . 551a vmacchng(0); . 540a #ifdef TIOCLGET /* stop */ case 't': tail("stop"); if (!ldisc) error("Old tty driver|Not using new tty driver/shell"); c = exclam(); eol(); if (!c) ckaw(); eol(); onsusp(); continue; #endif . 491a vmacchng(0); . 451a ckaw(); ignore(quickly()); . 450d 433a */ . 431a tostop(); /* replaced by tostop . 381a vmacchng(0); . 343a vmacchng(0); . 335c mapcmd(0, 0); . 298a vmacchng(0); . 286a inappend = 0; . 285a inappend = 1; . 283a vmacchng(0); . 239a editcmd: . 229a vmacchng(0); . 218a inappend = 0; . 217a inappend = 1; . 215a vmacchng(0); . 167a vmacchng(0); . 158a inappend = 0; . 157a inappend = 1; . 155a vmacchng(0); . 140c switch(peekchar()) { case 'b': /* abbreviate */ tail("abbreviate"); setnoaddr(); mapcmd(0, 1); anyabbrs = 1; continue; case 'r': . w q '-*-END-*-' ed - ex_cmds2.c << '-*-END-*-' 529a */ . 527a tostop(); /* replaced by the ostop above . 509a */ . 507a tostart(); /* replaced by ostart. . 506c if (Peekkey != ':') { . 381c return (endcmd(peekchar()) && peekchar() != '"'); . 279a case '"': comment(); setflav(); return; . 234a isalt = (strcmp(altfile, args)==0) + 1; . 230a extern short isalt; /* defined in ex_io.c */ . 161c inappend = inglobal = 0; . 136a */ . 134a /* ostop should be doing this . 121,124d 104a if (laste) { laste = 0; sync(); } . 41a case '"': . w q '-*-END-*-' ed - ex_cmdsub.c << '-*-END-*-' 1173c if (eq(src, mp[slot].cap) || eq(src, mp[slot].mapto)) . 1136a #ifdef TRACE if (trace) fprintf(trace, "addmac(src='%s', dest='%s', dname='%s', mp=%x\n", src, dest, dname, mp); #endif . 1096c } else if (endcmd(c) && c!='"') { . 1080a *p = 0; . 1072,1077c } else if (!un && any(c, " \t")) { /* End of lhs */ break; } else if (endcmd(c) && c!='"') { . 1052a if (un) error("Missing lhs"); . 1046c mp = ab ? abbrevs : exclam() ? immacs : arrows; . 1040c char lhs[100], rhs[100]; /* max sizes resp. */ . 1038a int ab; /* true if this is abbr command */ . 1037c mapcmd(un, ab) . 988c /* * Defensive programming - after a munged undadot. * Also handle empty buffer case. */ if ((dot <= zero || dot > dol) && dot != dol) . 585c extern char *ncols['z'-'a'+2]; . 562a /* Rest of tag if abbreviated */ while (!iswhite(*cp)) cp++; . 544c if ((*lp || !iswhite(*cp)) && (value(TAGLENGTH)==0 || lp-lasttag < value(TAGLENGTH))) { . 526a tfcount++; . 216a if (FIXUNDO) vundkind = VMANY; . 215a if (FIXUNDO) undap1 = undap2 = addr1; . 14a static jnoop(); . 5a #include "ex_vis.h" . w q '-*-END-*-' ed - ex_data.c << '-*-END-*-' 69d 64a "taglength", "tl", NUMERIC, 0, 0, 0, "tags", "tag", STRING, 0, 0, tags, . 63d 53a "readonly", "ro", ONOFF, 0, 0, 0, . 48a "mesg", 0, ONOFF, 1, 1, 0, . w q '-*-END-*-' ed - ex_io.c << '-*-END-*-' 973a if (slevel <= 0) ttyindes = saveinp; . 968d 960c short slevel; short ttyindes; . 936a if(kflag) crblock(perm, genbuf, nib, cntch); . 922a if(kflag) crblock(perm, genbuf, nib, cntch); . 894d 876a while(fp < &genbuf[ninbuf]) { if (*fp++ & 0200) { if (kflag) crblock(perm, genbuf, ninbuf+1, cntch); break; } } fp = genbuf; cntch += ninbuf+1; . 870a lp++; . 543,854d 484a if (value(READONLY)) error(" File is read only"); . 483a case EDF: if (value(READONLY)) error(" File is read only"); break; . 465c if (!exclam && (!value(WRITEANY) || value(READONLY))) switch (edfile()) { . 324a if (xflag) break; . 141c if (any(peekchar(), "#%|")) . 86a if (value(READONLY)) printf(" [Read only]"); . 46a if (c == 'e' || c == 'E') altdot = lineDOT(); . 45c wasalt = (isalt > 0) ? isalt-1 : 0; isalt = 0; . 18a short isalt; . 9c * File input/output, source, preserve and recover . w q '-*-END-*-' ed - ex_put.c << '-*-END-*-' 902a } #ifdef TIOCLGET /* * We have just gotten a susp. Suspend and prepare to resume. */ onsusp() { ttymode f; f = setty(normf); vnfl(); putpad(TE); flush(); signal(SIGTSTP, SIG_DFL); kill(0, SIGTSTP); /* the pc stops here */ signal(SIGTSTP, onsusp); vcontin(0); setty(f); if (!inopen) error(0); else { if (vcnt < 0) { vcnt = -vcnt; if (state == VISUAL) vclear(); else if (state == CRTOPEN) vcnt = 0; } vdirty(0, LINES); vrepaint(cursor); } . 892a # endif # ifdef TIOCLGET ioctl(i, TIOCSLTC, &nlttyc); # endif #else /* USG 3 very simple: just set everything */ ioctl(i, TCSETAW, &tty); . 890,891c # endif # ifdef TIOCGETC /* Update the other random chars while we're at it. */ . 888c # else /* We have to. Too bad. */ . 879,886c #ifndef USG3TTY # ifdef USG /* Bug in USG tty driver, put out a DEL as a patch. */ if (tty.sg_ospeed >= B1200) write(1, "\377", 1); # endif # ifdef TIOCSETN /* Don't flush typeahead if we don't have to */ . 874a /* * sTTY: set the tty modes on file descriptor i to be what's * currently in global "tty". (Also use nttyc if needed.) */ . 872a if ((tn=ttyname(0)) == NULL && (tn=ttyname(1)) == NULL && (tn=ttyname(2)) == NULL) tn = "/dev/tty"; strcpy(ttynbuf, tn); stat(ttynbuf, &sbuf); ttymesg = sbuf.st_mode & 0777; . 871a # endif # ifdef TIOCLGET ioctl(i, TIOCGLTC, &olttyc); nlttyc = olttyc; # endif #else ioctl(i, TCGETA, &tty); . 869c # ifdef TIOCGETC . 867a #ifndef USG3TTY . 866a char *tn; struct stat sbuf; . 859a #else if (tty.c_lflag & ICANON) ttcharoff(); tty = f; #endif . 856,858c # ifdef TIOCLGET nlttyc = olttyc; # endif } else ttcharoff(); . 853,854c #ifndef USG3TTY if (f == normf) { . 851a #else ttymode ot; ot = tty; #endif . 850a #ifndef USG3TTY . 849c ttymode f; . 847a ttymode . 836c ttymode f; . 807a if (!value(MESG)) chmod(ttynbuf, ttymesg); . 805a tostop(); } /* Actions associated with putting the terminal in the right mode. */ tostop() { . 803a #else pfast = (f.c_oflag & OCRNL) == 0; #endif . 802a #ifndef USG3TTY . 800c ttymode f; . 796a * Turn off start/stop chars if they aren't the default ^S/^Q. * This is so idiots who make esc their start/stop don't lose. * We always turn off quit since datamedias send ^\ for their * right arrow key. */ #ifdef TIOCGETC ttcharoff() { nttyc.t_quitc = '\377'; if (nttyc.t_startc != CTRL(q)) nttyc.t_startc = '\377'; if (nttyc.t_stopc != CTRL(s)) nttyc.t_stopc = '\377'; # ifdef TIOCLGET nlttyc.t_suspc = '\377'; /* ^Z */ nlttyc.t_dsuspc = '\377'; /* ^Y */ nlttyc.t_flushc = '\377'; /* ^O */ nlttyc.t_lnextc = '\377'; /* ^V */ # endif } #endif #ifdef USG3TTY ttcharoff() { tty.c_cc[VQUIT] = '\377'; # ifdef VSTART /* * The following is sample code if USG ever lets people change * their start/stop chars. As long as they can't we can't get * into trouble so we just leave them alone. */ if (tty.c_cc[VSTART] != CTRL(q)) tty.c_cc[VSTART] = '\377'; if (tty.c_cc[VSTOP] != CTRL(s)) tty.c_cc[VSTOP] = '\377'; # endif } #endif /* . 795a /* actions associated with putting the terminal in open mode */ tostart() { putpad(VS); putpad(KS); if (!value(MESG)) chmod(ttynbuf, 0611); /* 11 = urgent only allowed */ } . 790,791c tostart(); . 786,788d 784c f = tty; tty = normf; tty.c_iflag &= ~ICRNL; tty.c_lflag &= ~(ECHO|ICANON); tty.c_oflag &= ~TAB3; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 1; ttcharoff(); . 781,782c tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) | # ifdef CBREAK CBREAK; # else RAW; # endif # ifdef TIOCGETC ttcharoff(); # endif . 779a #ifndef USG3TTY . 774c ttymode f; . 771a ttymode . 750a #else tty = normf; tty.c_oflag &= ~(ONLCR|TAB3); tty.c_lflag &= ~ECHO; #endif . 749a #ifndef USG3TTY . 681,690d 671c *obp++ = c & 0177; . 565,568d 532c i = tabcol(outcol, value(HARDTABS)); . 499c if (xNL && pfast) tputs(xNL, 0, plodput); else plodput('\n'); . 491c if (xNL) tputs(xNL, 0, plodput); else plodput('\n'); . 489c /* * BUG: this doesn't take the (possibly long) length * of xCR into account. */ if (xCR) tputs(xCR, 0, plodput); else plodput('\r'); . 459c i = destcol % value(HARDTABS) + destcol / value(HARDTABS); . 457c } else /* * No home and no up means it's impossible, so we return an * incredibly big number to make cursor motion win out. */ if (!UP && destline < outline) return (500); . 451c if (i + k + 2 < j && (k<=0 || UP)) { . 449a /* * Quickly consider homing down and moving from there. * Assume cost of LL is 2. */ . 446c /* * Decision. We may not have a choice if no UP. */ if (i + destline < j || (!UP && destline < outline)) { /* * Cheaper to home. Do it now and pretend it's a * regular local motion. */ . 441c j = i + 1; /* impossibly expensive */ /* k is the absolute value of vertical distance */ . 439c i = j = outcol - destcol; /* cheaper to backspace */ . 437c } else /* leftward motion only works if we can backspace. */ . 431,434c /* * j is cost to move locally without homing */ if (destcol >= outcol) { /* if motion is to the right */ j = destcol / value(HARDTABS) - outcol / value(HARDTABS); if (GT && j) j += destcol % value(HARDTABS); . 428c i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS)); . 426a /* * i is the cost to home and tab/space to the right to * get to the proper column. This assumes ND space costs * 1 char. So i+destcol is cost of motion with home. */ . 425a /* * Consider homing and moving down/right from there, vs moving * directly with local motions to the right spot. */ . 369c /* * The following linefeed (or simulation thereof) * is supposed to scroll up the screen, since we * are on the bottom line. We make the assumption * that linefeed will scroll. If ns is in the * capability list this won't work. We should * probably have an sc capability but sf will * generally take the place if it works. * * Superbee glitch: in the middle of the screen we * have to use esc B (down) because linefeed screws up * in "Efficient Paging" (what a joke) mode (which is * essential in some SB's because CRLF mode puts garbage * in at end of memory), but you must use linefeed to * scroll since down arrow won't go past memory end. * I turned this off after recieving Paul Eggert's * Superbee description which wins better. */ if (xNL /* && !XB */ && pfast) tputs(xNL, 0, putch); else putch('\n'); . 347,348c if (xCR) tputs(xCR, 0, putch); else putch('\r'); if (xNL) tputs(xNL, 0, putch); else putch('\n'); . 197,202c static char linb[66]; static char *linp = linb; . w q '-*-END-*-' ed - ex_re.c << '-*-END-*-' 786c case CEOFC: . 704,707d 650c *ep++ = CEOFC; . 525c *ep++ = CEOFC; . 310c if (cflag == 0) . 198c cflag = !cflag; . 186a if (subre.Expbuf[0] == 0) error("No previous substitute re|No previous substitute to repeat"); . 177c cflag = 0; . 160c gsubf = cflag = 0; . 148c if (stotal == 0 && !inglobal && !cflag) . 107c bool cflag; . w q '-*-END-*-' ed - ex_re.h << '-*-END-*-' 62c #define CEOFC 17 . w q '-*-END-*-' ed - ex_set.c << '-*-END-*-' 76a if (op == &options[PROMPT]) oprompt = 1 - no; . w q '-*-END-*-' ed - ex_subr.c << '-*-END-*-' 770d 686a /* * Return the column number that results from being in column col and * hitting a tab, where tabs are set every ts columns. Work right for * the case where col > COLUMNS, even if ts does not divide COLUMNS. */ tabcol(col, ts) int col, ts; { int offset, result; if (col >= COLUMNS) { offset = COLUMNS * (col/COLUMNS); col -= offset; } else offset = 0; result = col + ts - (col % ts) + offset; return (result); } . 446c *addr = n | oldglobmk; . 440a oldglobmk = *addr & 1; . 439a register oldglobmk; . 181a else if (c=='"') comment(); . 58a /* * Ignore a comment to the end of the line. * This routine eats the trailing newline so don't call newline(). */ comment() { register int c; do { c = getchar(); } while (c != '\n' && c != EOF); if (c == EOF) ungetchar(c); } . w q '-*-END-*-' ed - ex_temp.c << '-*-END-*-' 574a } /* * Encryption routines. These are essentially unmodified from ed. */ /* * crblock: encrypt/decrypt a block of text. * buf is the buffer through which the text is both input and * output. nchar is the size of the buffer. permp is a work * buffer, and startn is the beginning of a sequence. */ crblock(permp, buf, nchar, startn) char *permp; char *buf; int nchar; long startn; { register char *p1; int n1; int n2; register char *t1, *t2, *t3; t1 = permp; t2 = &permp[256]; t3 = &permp[512]; n1 = startn&0377; n2 = (startn>>8)&0377; p1 = buf; while(nchar--) { *p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1; n1++; if(n1==256){ n1 = 0; n2++; if(n2==256) n2 = 0; } p1++; } } /* * makekey: initialize buffers based on user key a. */ makekey(a, b) char *a, *b; { register int i; long t; char temp[KSIZE + 1]; for(i = 0; i < KSIZE; i++) temp[i] = *a++; time(&t); t += getpid(); for(i = 0; i < 4; i++) temp[i] ^= (t>>(8*i))&0377; crinit(temp, b); } /* * crinit: besides initializing the encryption machine, this routine * returns 0 if the key is null, and 1 if it is non-null. */ crinit(keyp, permp) char *keyp, *permp; { register char *t1, *t2, *t3; register i; int ic, k, temp; unsigned random; char buf[13]; long seed; t1 = permp; t2 = &permp[256]; t3 = &permp[512]; if(*keyp == 0) return(0); strncpy(buf, keyp, 8); while (*keyp) *keyp++ = '\0'; buf[8] = buf[0]; buf[9] = buf[1]; domakekey(buf); seed = 123; for (i=0; i<13; i++) seed = seed*buf[i] + i; for(i=0;i<256;i++){ t1[i] = i; t3[i] = 0; } for(i=0; i<256; i++) { seed = 5*seed + buf[i%13]; random = seed % 65521; k = 256-1 - i; ic = (random&0377) % (k+1); random >>= 8; temp = t1[k]; t1[k] = t1[ic]; t1[ic] = temp; if(t3[k]!=0) continue; ic = (random&0377) % k; while(t3[ic]!=0) ic = (ic+1) % k; t3[k] = ic; t3[ic] = k; } for(i=0; i<256; i++) t2[t1[i]&0377] = i; return(1); } /* * domakekey: the following is the major nonportable part of the encryption * mechanism. A 10 character key is supplied in buffer. * This string is fed to makekey (an external program) which * responds with a 13 character result. This result is placed * in buffer. */ domakekey(buffer) char *buffer; { int pf[2]; if (pipe(pf)<0) pf[0] = pf[1] = -1; if (fork()==0) { close(0); close(1); dup(pf[0]); dup(pf[1]); execl("/usr/lib/makekey", "-", 0); execl("/lib/makekey", "-", 0); exit(1); } write(pf[1], buffer, 10); if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13) error("crypt: cannot generate key"); close(pf[0]); close(pf[1]); /* end of nonportable part */ . 219a if (*bp > NMBLKS) error(" Tmp file too large"); . 176,177c if (oblock >= 0) { if(xtflag) { /* * Encrypt block before writing, so some devious * person can't look at temp file while editing. */ p1 = obuff; p2 = crbuf; n = CRSIZE; while(n--) *p2++ = *p1++; crblock(tperm, crbuf, CRSIZE, (long)0); blkio(oblock, crbuf, write); } else blkio(oblock, obuff, write); } . 173a if(xtflag) crblock(tperm, ibuff, CRSIZE, (long)0); . 170a } . 169c if (ichanged) { if(xtflag) crblock(tperm, ibuff, CRSIZE, (long)0); . 164a if(xtflag) crblock(tperm, ibuff2, CRSIZE, (long)0); . 161a } . 160c if (ichang2) { if(xtflag) crblock(tperm, ibuff2, CRSIZE, (long)0); . 139a register char *p1, *p2; register int n; . w q '-*-END-*-' ed - ex_tty.c << '-*-END-*-' 117c namp = "albcbtcdceclcmcrdcdldmdoedeik0k1k2k3k4k5k6k7k8k9hoicimipkdkekhklkrkskullndnlpcsesfsosrtatetiupvbvsve"; . 111c namp = "ambsdadbeohchzinmincnsosulxbxnxtxx"; . 92,96d 82c if (tgoto(CM, 2, 2)[0] == 'O') /* OOPS */ . 80c if (COLUMNS <= 4) . 75a #ifdef TIOCLGET /* * Now map users susp char to ^Z, being careful that the susp * overrides any arrow key, but only for hackers (=new tty driver). */ { static char sc[2]; int i, fnd; ioctl(0, TIOCGETD, &ldisc); if (ldisc == NTTYDISC) { sc[0] = olttyc.t_suspc; sc[1] = 0; if (olttyc.t_suspc == CTRL(z)) { for (i=0; i<=4; i++) if (arrows[i].cap[0] == CTRL(z)) addmac(sc, NULL, NULL, arrows); } else addmac(sc, "\32", "susp", arrows); } } #endif . 42c char *tgoto(); . 34c &AM, &BS, &DA, &DB, &EO, &HC, &HZ, &IN, &MI, &NC, &NS, &OS, &UL, &XB, &XN, &XT, &XX . 31c &ND, &xNL, &xPC, &SE, &SF, &SO, &SR, &TA, &TE, &TI, &UP, &VB, &VS, &VE . 28c &AL, &BC, &BT, &CD, &CE, &CL, &CM, &xCR, &DC, &DL, &DM, &DO, &ED, &EI, . 23a #else if (ioctl(1, TCGETA, &tty) < 0) return; if (ospeed != tty.c_cflag & CBAUD) value(SLOWOPEN) = (tty.c_cflag & CBAUD) < B1200; ospeed = tty.c_cflag & CBAUD; normf = tty; UPPERCASE = (tty.c_iflag & IUCLC) != 0; GT = (tty.c_oflag & TABDLY) != TAB3 && !XT; NONL = (tty.c_oflag & OCRNL) == 0; #endif . 14a #ifndef USG3TTY . w q '-*-END-*-' ed - ex_tty.h << '-*-END-*-' 132a int maphopcnt; /* check for infinite mapping loops */ bool anyabbrs; /* true if abbr or unabbr has been done */ char ttynbuf[20]; /* result of ttyname() */ int ttymesg; /* original mode of users tty */ . 130a struct maps abbrevs[MAXNOMACS]; /* for word abbreviations */ int ldisc; /* line discipline for ucb tty driver */ . 111a ttymode normf; /* Restore tty flags to this (someday) */ bool normtty; /* Have to restore normal mode from normf */ ttymode ostart(), setty(), unixex(); . 108,110d 105,106c /* * There are several kinds of tty drivers to contend with. These include: * (1) V6: no CBREAK, no ioctl. (Include PWB V1 here). * (2) V7 research: has CBREAK, has ioctl, and has the tchars (TIOCSETC) * business to change start, stop, etc. chars. * (3) USG V2: Basically like V6 but RAW mode is like V7 RAW. * (We treat it as V6.) * (4) USG V3: equivalent to V7 but totally incompatible. * (5) Berkeley: has ltchars in addition to all of V7. * * The following attempts to decide what we are on, and declare * some variables in the appropriate format. The wierd looking one (ttymode) * is the thing we pass to sTTY and family to turn "RAW" mode on or off * when we go into or out of visual mode. In V7/V6 it's just the flags word * to stty. In USG V3 it's the whole tty structure. */ #ifdef USG3TTY /* USG V3 */ struct termio tty; /* Use this one structure to change modes */ typedef struct termio ttymode; /* Mode to contain tty flags */ #else /* All others */ struct sgttyb tty; /* Always stty/gtty using this one structure */ typedef int ttymode; /* Mode to contain tty flags */ # ifdef TIOCSETC /* V7 */ struct tchars ottyc, nttyc; /* For V7 character masking */ # endif # ifdef TIOCLGET /* Berkeley */ struct ltchars olttyc, nlttyc; /* More of tchars style stuff */ # endif . 86a bool XX; /* Tektronix 4025 insert line */ . 84a bool XB; /* Beehive (no escape key, simulate with f1) */ . 82a bool NS; /* No scroll - linefeed at bottom won't scroll */ . 58a char *xNL; /* Line feed (new line) */ . 37a char *xCR; /* P Carriage return */ . w q '-*-END-*-' ed - ex_tune.h << '-*-END-*-' 109c #define ATTN (-2) . 40a #define CRSIZE 512 . 37a #define CRSIZE 1024 . 16c #define EXSTRINGS libpath(ex3.4strings) . 13,14c #define EXRECOVER libpath(ex3.4recover) #define EXPRESERVE libpath(ex3.4preserve) . w q '-*-END-*-' cat > ex_unix.c << '-*-END-*-' /* Copyright (c) 1979 Regents of the University of California */ #include "ex.h" #include "ex_temp.h" #include "ex_tty.h" #include "ex_vis.h" /* * Unix escapes, filtering */ /* * First part of a shell escape, * parse the line, expanding # and % and ! and printing if implied. */ unix0(warn) bool warn; { register char *up, *fp; register short c; char printub, puxb[UXBSIZE + sizeof (int)]; printub = 0; CP(puxb, uxb); c = getchar(); if (c == '\n' || c == EOF) error("Incomplete shell escape command@- use 'shell' to get a shell"); up = uxb; do { switch (c) { case '\\': if (any(peekchar(), "%#!")) c = getchar(); default: if (up >= &uxb[UXBSIZE]) { tunix: uxb[0] = 0; error("Command too long"); } *up++ = c; break; case '!': fp = puxb; if (*fp == 0) { uxb[0] = 0; error("No previous command@to substitute for !"); } printub++; while (*fp) { if (up >= &uxb[UXBSIZE]) goto tunix; *up++ = *fp++; } break; case '#': fp = altfile; if (*fp == 0) { uxb[0] = 0; error("No alternate filename@to substitute for #"); } goto uexp; case '%': fp = savedfile; if (*fp == 0) { uxb[0] = 0; error("No filename@to substitute for %%"); } uexp: printub++; while (*fp) { if (up >= &uxb[UXBSIZE]) goto tunix; *up++ = *fp++ | QUOTE; } break; } c = getchar(); } while (c == '"' || c == '|' || !endcmd(c)); if (c == EOF) ungetchar(c); *up = 0; if (!inopen) resetflav(); if (warn) ckaw(); if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) { xchng = chng; vnfl(); printf(mesg("[No write]|[No write since last change]")); noonl(); flush(); } else warn = 0; if (printub) { if (uxb[0] == 0) error("No previous command@to repeat"); if (inopen) { splitw++; vclean(); vgoto(WECHO, 0); } if (warn) vnfl(); if (hush == 0) lprintf("!%s", uxb); if (inopen && Outchar != termchar) { vclreol(); vgoto(WECHO, 0); } else putnl(); flush(); } } /* * Do the real work for execution of a shell escape. * Mode is like the number passed to open system calls * and indicates filtering. If input is implied, newstdin * must have been setup already. */ ttymode unixex(opt, up, newstdin, mode) char *opt, *up; int newstdin, mode; { int pvec[2]; ttymode f; signal(SIGINT, SIG_IGN); #ifdef TIOCLGET if (dosusp) signal(SIGTSTP, SIG_DFL); #endif if (inopen) f = setty(normf); if ((mode & 1) && pipe(pvec) < 0) { /* Newstdin should be io so it will be closed */ if (inopen) setty(f); error("Can't make pipe for filter"); } #ifndef VFORK pid = fork(); #else pid = vfork(); #endif if (pid < 0) { if (mode & 1) { close(pvec[0]); close(pvec[1]); } setrupt(); error("No more processes"); } if (pid == 0) { if (mode & 2) { close(0); dup(newstdin); close(newstdin); } if (mode & 1) { close(pvec[0]); close(1); dup(pvec[1]); if (inopen) { close(2); dup(1); } close(pvec[1]); } if (io) close(io); if (tfile) close(tfile); #ifndef VMUNIX close(erfile); #endif signal(SIGHUP, oldhup); signal(SIGQUIT, oldquit); if (ruptible) signal(SIGINT, SIG_DFL); execl(svalue(SHELL), "sh", opt, up, (char *) 0); printf("No %s!\n", svalue(SHELL)); error(NOSTR); } if (mode & 1) { io = pvec[0]; close(pvec[1]); } if (newstdin) close(newstdin); return (f); } /* * Wait for the command to complete. * F is for restoration of tty mode if from open/visual. * C flags suppression of printing. */ unixwt(c, f) bool c; ttymode f; { waitfor(); #ifdef TIOCLGET if (dosusp) signal(SIGTSTP, onsusp); #endif if (inopen) setty(f); setrupt(); if (!inopen && c && hush == 0) { printf("!\n"); flush(); termreset(); gettmode(); } } /* * Setup a pipeline for the filtration implied by mode * which is like a open number. If input is required to * the filter, then a child editor is created to write it. * If output is catch it from io which is created by unixex. */ filter(mode) register int mode; { static int pvec[2]; register ttymode f; register int lines = lineDOL(); mode++; if (mode & 2) { signal(SIGINT, SIG_IGN); if (pipe(pvec) < 0) error("Can't make pipe"); pid = fork(); io = pvec[0]; if (pid < 0) { setrupt(); close(pvec[1]); error("No more processes"); } if (pid == 0) { setrupt(); io = pvec[1]; close(pvec[0]); putfile(); exit(0); } close(pvec[1]); io = pvec[0]; setrupt(); } f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); if (mode == 3) { delete(0); addr2 = addr1 - 1; } if (mode & 1) { if(FIXUNDO) undap1 = undap2 = addr2+1; ignore(append(getfile, addr2)); } close(io); io = -1; unixwt(!inopen, f); netchHAD(lines); } /* * Set up to do a recover, getting io to be a pipe from * the recover process. */ recover() { static int pvec[2]; if (pipe(pvec) < 0) error(" Can't make pipe for recovery"); pid = fork(); io = pvec[0]; if (pid < 0) { close(pvec[1]); error(" Can't fork to execute recovery"); } if (pid == 0) { close(2); dup(1); close(1); dup(pvec[1]); close(pvec[1]); execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0); close(1); dup(2); error(" No recovery routine"); } close(pvec[1]); } /* * Wait for the process (pid an external) to complete. */ waitfor() { do rpid = wait(&status); while (rpid != pid && rpid != -1); status = (status >> 8) & 0377; } /* * The end of a recover operation. If the process * exits non-zero, force not edited; otherwise force * a write. */ revocer() { waitfor(); if (pid == rpid && status != 0) edited = 0; else change(); } '-*-END-*-' ed - ex_v.c << '-*-END-*-' 260a if (undadot <= zero || undadot > dol) undadot = zero+1; . 177a if (NS && !SF) { if (initev) goto toopen; error("Visual requires scrolling"); } . 156c register ttymode f; . 131c ttymode f; . 56c register ttymode f; . w q '-*-END-*-' ed - ex_vadj.c << '-*-END-*-' 366a vscroll(cnt); . 365d 118a #ifdef TRACE if (trace) fprintf(trace, "after pline in vreopen\n"); #endif . 117a #ifdef TRACE if (trace) fprintf(trace, "before pline in vreopen\n"); #endif . w q '-*-END-*-' ed - ex_vars.h << '-*-END-*-' 40c #define NOPTS 40 . 13,38c #define MESG 12 #define NUMBER 13 #define OPEN 14 #define OPTIMIZE 15 #define PARAGRAPHS 16 #define PROMPT 17 #define READONLY 18 #define REDRAW 19 #define REMAP 20 #define REPORT 21 #define SCROLL 22 #define SECTIONS 23 #define SHELL 24 #define SHIFTWIDTH 25 #define SHOWMATCH 26 #define SLOWOPEN 27 #define TABSTOP 28 #define TAGLENGTH 29 #define TAGS 30 #define TERM 31 #define TERSE 32 #define TIMEOUT 33 #define TTYTYPE 34 #define WARN 35 #define WINDOW 36 #define WRAPSCAN 37 #define WRAPMARGIN 38 #define WRITEANY 39 . w q '-*-END-*-' ed - ex_vget.c << '-*-END-*-' 496,497c register line *p; if (!trace) return; fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n", s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2)); fprintf(trace, " undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n", lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol)); fprintf(trace, " ["); for (p=zero+1; p<=truedol; p++) fprintf(trace, "%o ", *p); fprintf(trace, "]\n"); . 492a visdump(s) char *s; { register int i; if (!trace) return; fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n", s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO); fprintf(trace, " vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n", vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero); for (i=0; i ^C */ c = CTRL(c); Peek2key = 0; break; case 'p': /* f1 -> esc */ Peek2key = 0; break; } } #endif . 90c if (read(slevel == 0 ? 0 : ttyindes, &ch, 1) != 1) { . 86a vch_mac = VC_NOTINMAC; . 72a #ifdef BEEHIVE if (Peek2key) { c = Peek2key; Peek2key = 0; return (c); } #endif . 65a #define BEEHIVE #ifdef BEEHIVE static char Peek2key; #endif extern short slevel, ttyindes; . w q '-*-END-*-' ed - ex_vis.h << '-*-END-*-' 135a /* * State information for undoing of macros. The basic idea is that * if the macro does only 1 change or even none, we don't treat it * specially. If it does 2 or more changes we want to be able to * undo it as a unit. We remember how many changes have been made * within the current macro. (Remember macros can be nested.) */ #define VC_NOTINMAC 0 /* Not in a macro */ #define VC_NOCHANGE 1 /* In a macro, no changes so far */ #define VC_ONECHANCE 2 /* In a macro, one change so far */ #define VC_MANYCHANGE 3 /* In a macro, at least 2 changes so far */ short vch_mac; /* Change state - one of the above */ . 3c * Ex version 3 . w q '-*-END-*-' ed - ex_vmain.c << '-*-END-*-' 1040c vundo(1); . 852a getDOT(); . 839a * ^Z: suspend editor session and temporarily return * to shell. Only works on Berkeley tty driver. */ case CTRL(z): forbid(dosusp == 0 || !ldisc); vsave(); oglobp = globp; globp = "stop"; goto gogo; #endif /* . 838a #ifdef TIOCLGET . 692a vmacchng(1); . 691a /* * If we just did a macro the whole buffer is in * the undo save area. We don't want to put THAT. */ forbid (vundkind == VMANY && undkind==UNDALL); . 674a #endif . 673a #ifdef notdef . 646a /* * If we are in the middle of a macro, throw away * the rest and fix up undo. * This code copied from getbr(). */ if (vmacp) { vmacp = 0; if (inopen == -1) /* don't screw up undo for esc esc */ vundkind = VMANY; inopen = 1; /* restore old setting now that macro done */ } . 576a vmacchng(1); . 508a setLAST(); . 490a vmacchng(1); . 455a vmacchng(1); . 403c dot -= vcline - 2 + (cnt-1)*basWLINES; . 400,401d 388c dot += (vcnt - vcline) - 2 + (cnt-1)*basWLINES; . 385,386d 381c * Count repeats. . 146a if (++maphopcnt > 256) error("Infinite macro loop"); . 123a maphopcnt = 0; . 26a vch_mac = VC_NOTINMAC; . w q '-*-END-*-' ed - ex_voperate.c << '-*-END-*-' 415a vmacchng(1); . 113a vmacchng(1); . 108a vmacchng(1); . w q '-*-END-*-' ed - ex_vops.c << '-*-END-*-' 148a break; } } /* * Routine to handle a change inside a macro. * Fromvis is true if we were called from a visual command (as * opposed to an ex command). This has nothing to do with being * in open/visual mode as :s/foo/bar is not fromvis. */ vmacchng(fromvis) bool fromvis; { line *savedot, *savedol; char *savecursor; int nlines, more; register line *a1, *a2; char ch; /* DEBUG */ int copyw(), copywR(); if (!inopen) return; if (!vmacp) vch_mac = VC_NOTINMAC; #ifdef TRACE if (trace) fprintf(trace, "vmacchng, vch_mac=%d, linebuf='%s', *dot=%o\n", vch_mac, linebuf, *dot); #endif if (vmacp && fromvis) vsave(); #ifdef TRACE if (trace) fprintf(trace, "after vsave, linebuf='%s', *dot=%o\n", linebuf, *dot); #endif switch(vch_mac) { case VC_NOCHANGE: vch_mac = VC_ONECHANGE; break; case VC_ONECHANGE: /* Save current state somewhere */ #ifdef TRACE vudump("before vmacchng hairy case"); #endif savedot = dot; savedol = dol; savecursor = cursor; nlines = dol - zero; while ((line *) endcore - truedol < nlines) morelines(); copyw(truedol+1, zero+1, nlines); truedol += nlines; #ifdef TRACE visdump("before vundo"); #endif /* Restore state as it was at beginning of macro */ vundo(0); #ifdef TRACE visdump("after vundo"); vudump("after vundo"); #endif /* Do the saveall we should have done then */ saveall(); #ifdef TRACE vudump("after saveall"); #endif /* Restore current state from where saved */ more = savedol - dol; /* amount we shift everything by */ if (more) (*(more>0 ? copywR : copyw))(savedol+1, dol+1, truedol-dol); unddol += more; truedol += more; truedol -= nlines; copyw(zero+1, truedol+1, nlines); dot = savedot; dol = savedol ; cursor = savecursor; vch_mac = VC_MANYCHANGE; /* Arrange that no further undo saving happens within macro */ otchng = tchng; /* Copied this line blindly - bug? */ inopen = -1; /* no need to save since it had to be 1 or -1 before */ vundkind = VMANY; #ifdef TRACE vudump("after vmacchng"); #endif break; case VC_NOTINMAC: case VC_MANYCHANGE: /* Nothing to do for various reasons. */ . 118a if (!show) break; . 105,106c if (show) { vcline = cnt; vrepaint(vmcurs); } . 100c if (show) vjumpto(dot, NOSTR, '.'); . 95c if (show && (vundkind != VMCHNG || addr != dot)) . 91,92c if (show) if (undkind == UNDMOVE) vdirty(0, LINES); else vreplace(undap1 - addr, undap2 - undap1, undkind == UNDPUT ? 0 : unddol - dol); . 56c vundo(show) bool show; /* if true update the screen */ . 52a cursor = linebuf; . w q '-*-END-*-' ed - ex_vops2.c << '-*-END-*-' 720c if (Outchar != termchar) Outchar = OO; . 714d 710d 704a flush(); . 596a /* * Word abbreviation mode. */ cstr[0] = c; if (anyabbrs && gcursor > ogcursor && !wordch(cstr) && wordch(gcursor-1)) { int wdtype, abno; cstr[1] = 0; wdkind = 1; cp = gcursor - 1; for (wdtype = wordch(cp - 1); cp > ogcursor && wordof(wdtype, cp - 1); cp--) ; *gcursor = 0; for (abno=0; abbrevs[abno].mapto; abno++) { if (eq(cp, abbrevs[abno].cap)) { macpush(cstr, 0); macpush(abbrevs[abno].mapto); goto vbackup; } } } . 595a dontbreak:; . 592,594c if (/* c <= ' ' && */ value(WRAPMARGIN) && outcol >= OCOLUMNS - value(WRAPMARGIN)) { /* * At end of word and hit wrapmargin. * Move the word to next line and keep going. */ wdkind = 1; *gcursor++ = c; *gcursor = 0; /* * Find end of previous word if we are past it. */ for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--) ; if (outcol - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) { /* * Find beginning of previous word. */ for (; cp>ogcursor && !isspace(cp[-1]); cp--) ; if (cp <= ogcursor) { /* * There is a single word that * is too long to fit. Just * let it pass, but beep for * each new letter to warn * the luser. */ c = *--gcursor; *gcursor = 0; beep(); goto dontbreak; } /* * Save it for next line. */ macpush(cp, 0); cp--; } macpush("\n", 0); /* * Erase white space before the word. */ while (cp > ogcursor && isspace(cp[-1])) cp--; /* skip blank */ gobblebl = 3; goto vbackup; . 587,588c if (c != NL && !splitw) { if (c == ' ' && gobblebl) { . 547a #else if (c == tty.c_cc[VERASE] || c == tty.c_cc[VKILL]) { #endif . 546a #ifndef USG3TTY . 463a #else if (c == tty.c_cc[VERASE]) c = CTRL(h); else if (c == tty.c_cc[VKILL]) c = -1; #endif . 459a #ifndef USG3TTY . 450a if (++maphopcnt > 256) error("Infinite macro loop"); . 445c c = getkey(); if (c != ATTN) c &= (QUOTE|TRIM); ch = c; maphopcnt = 0; . 409a char cstr[2]; . w q '-*-END-*-' ed - ex_vops3.c << '-*-END-*-' 459c if (lf == vmove && wcursor > linebuf) . 372a else { strcLIN(sp); strcpy(scurs, genbuf); if (!lmatchp((line *) 0)) beep(); } . 329c parens = any(*cp, "()") ? "()" : any(*cp, "[]") ? "[]" : "{}"; . 325c for (cp = cursor; !any(*cp, "({[)}]");) . w q '-*-END-*-' ed - ex_vput.c << '-*-END-*-' 621c if (inssiz >= doomed + tabcol(tabstart, value(TABSTOP)) - tabstart) { . 545c inssiz = tabcol(inscol, value(TABSTOP)) - inscol; . 446c if (p < 0 || vtube[p] == cp) . 406c while (--i); . 402c register int i = tabcol(destcol, value(TABSTOP)) - destcol; . 118,121c if (DB) { vgoto(WECHO, 0); vputp(CD ? CD : CE, 1); } else { if (XT) { /* * This code basically handles the t1061 * where positioning at (0, 0) won't work * because the terminal won't let you put * the cursor on it's magic cookie. * * Should probably be XS above, or even a * new X? glitch, but right now t1061 is the * only terminal with XT. */ vgoto(WECHO, 0); vputp(DL, 1); } else { vigoto(WECHO, 0); vclreol(); } } . w q '-*-END-*-' ed - exrecover.c << '-*-END-*-' 179a #else ioctl(2, TCGETA, &tty); if (tty.c_lflag & ICANON) #endif . 177a #ifndef USG3TTY . w q '-*-END-*-' ed - makefile << '-*-END-*-' /rm -f.*NBINDIR/s/$/ ${DESTDIR}${NBINDIR}\/view/ /ln.*NBINDIR.*vi/a ln ${DESTDIR}${NBINDIR}/ex ${DESTDIR}${NBINDIR}/view . /rm -f.*{BINDIR}\/vi/a -rm -f ${DESTDIR}${BINDIR}/view . /ln.*{BINDIR}\/vi/a ln ${DESTDIR}${BINDIR}/ex ${DESTDIR}${BINDIR}/view . /ex_tty.o/s//& ex_unix.o/ 1c VERSION=3.4 . w q '-*-END-*-' ed - makeoptions << '-*-END-*-' 40c rm /tmp/foo.c . 35,37c $s/e[ ].*[ ]/e NOPTS / w! ex_vars.h q . 11,32c cc -E $* /tmp/$$.c >/tmp/foo.c ex - /tmp/foo.c <<'X' " delete all preprocessor output (# line, etc) g/^# /d set sh=/bin/csh " delete junk (all but data lines) g/^[ ]*$/d 1,/options/d /}/-1,$d " get rid of all of line but option name 1,$s/ "// 1,$s/".*// 1m$ " kludge since options start at 0 but num at 1 %!num $t0 " unkludge 1s/......../ 0 / " unkludge " make #define lines 1,$s/\(......\)\(.*\)/#define \U\2\L \1/ " get rid of extra blanks, turning into (single) tabs. 1,$s/ */ /g g/ */s// /g " filter through expand to make it line up nice %!expand -8\,24 " blank line and number of options. $i . 4,9c onintr ifintr cp ex_data.c /tmp/$$.c ex - /tmp/$$.c <<'%' g/^#include/d w q . w q '-*-END-*-'