/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #if !defined(lint) && defined(DOSCCS) static char *sccsid = "@(#)ex_subr.c 7.10.1 (2.11BSD) 1996/3/22"; #endif #include "ex.h" #include "ex_re.h" #include "ex_tty.h" #include "ex_vis.h" /* * Random routines, in alphabetical order. */ any(c, s) int c; register char *s; { register int x; while (x = *s++) if (x == c) return (1); return (0); } backtab(i) register int i; { register int j; j = i % value(SHIFTWIDTH); if (j == 0) j = value(SHIFTWIDTH); i -= j; if (i < 0) i = 0; return (i); } change() { tchng++; chng = tchng; } /* * Column returns the number of * columns occupied by printing the * characters through position cp of the * current line. */ column(cp) register char *cp; { if (cp == 0) cp = &linebuf[LBSIZE - 2]; return (qcolumn(cp, (char *) 0)); } /* * 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); } Copy(to, from, size) register char *from, *to; register int size; { if (size > 0) do *to++ = *from++; while (--size > 0); } copyw(to, from, size) register line *from, *to; register int size; { if (size > 0) do *to++ = *from++; while (--size > 0); } copywR(to, from, size) register line *from, *to; register int size; { while (--size >= 0) to[size] = from[size]; } ctlof(c) int c; { return (c == TRIM ? '?' : c | ('A' - 1)); } dingdong() { if (VB) putpad(VB); else if (value(ERRORBELLS)) putch('\207'); } fixindent(indent) int indent; { register int i; register char *cp; i = whitecnt(genbuf); cp = vpastwh(genbuf); if (*cp == 0 && i == indent && linebuf[0] == 0) { genbuf[0] = 0; return (i); } CP(genindent(i), cp); return (i); } filioerr(cp) char *cp; { register int oerrno = errno; lprintf("\"%s\"", cp); errno = oerrno; syserror(); } char * genindent(indent) register int indent; { register char *cp; for (cp = genbuf; indent >= value(TABSTOP); indent -= value(TABSTOP)) *cp++ = '\t'; for (; indent > 0; indent--) *cp++ = ' '; return (cp); } getDOT() { getline(*dot); } line * getmark(c) register int c; { register line *addr; for (addr = one; addr <= dol; addr++) if (names[c - 'a'] == (*addr &~ 01)) { return (addr); } return (0); } getn(cp) register char *cp; { register int i = 0; while (isdigit(*cp)) i = i * 10 + *cp++ - '0'; if (*cp) return (0); return (i); } ignnEOF() { register int c = getchar(); if (c == EOF) ungetchar(c); else if (c=='"') comment(); } iswhite(c) int c; { return (c == ' ' || c == '\t'); } junk(c) register int c; { if (c && !value(BEAUTIFY)) return (0); if (c >= ' ' && c != TRIM) return (0); switch (c) { case '\t': case '\n': case '\f': return (0); default: return (1); } } killed() { killcnt(addr2 - addr1 + 1); } killcnt(cnt) register int cnt; { if (inopen) { notecnt = cnt; notenam = notesgn = ""; return; } if (!notable(cnt)) return; printf("%d lines", cnt); if (value(TERSE) == 0) { printf(" %c%s", Command[0] | ' ', Command + 1); if (Command[strlen(Command) - 1] != 'e') putchar('e'); putchar('d'); } putNFL(); } lineno(a) line *a; { return (a - zero); } lineDOL() { return (lineno(dol)); } lineDOT() { return (lineno(dot)); } markDOT() { markpr(dot); } markpr(which) line *which; { if ((inglobal == 0 || inopen) && which <= endcore) { names['z'-'a'+1] = *which & ~01; if (inopen) ncols['z'-'a'+1] = cursor; } } markreg(c) register int c; { if (c == '\'' || c == '`') return ('z' + 1); if (c >= 'a' && c <= 'z') return (c); return (0); } /* * Mesg decodes the terse/verbose strings. Thus * 'xxx@yyy' -> 'xxx' if terse, else 'xxx yyy' * 'xxx|yyy' -> 'xxx' if terse, else 'yyy' * All others map to themselves. */ char * mesg(str) register char *str; { register char *cp; str = strcpy(genbuf, str); for (cp = str; *cp; cp++) switch (*cp) { case '@': if (value(TERSE)) *cp = 0; else *cp = ' '; break; case '|': if (value(TERSE) == 0) return (cp + 1); *cp = 0; break; } return (str); } /*VARARGS2*/ merror(seekpt, i) #ifdef VMUNIX char *seekpt; #else # ifdef lint char *seekpt; # else int seekpt; # endif #endif int i; { register char *cp = linebuf; if (seekpt == 0) return; merror1(seekpt); if (*cp == '\n') putnl(), cp++; if (inopen > 0 && CE) vclreol(); if (SO && SE) putpad(SO); printf(mesg(cp), i); if (SO && SE) putpad(SE); } merror1(seekpt) #ifdef VMUNIX char *seekpt; #else # ifdef lint char *seekpt; # else int seekpt; # endif #endif { #ifdef VMUNIX strcpy(linebuf, seekpt); #else lseek(erfile, (long) seekpt, 0); if (read(erfile, linebuf, 128) < 2) CP(linebuf, "ERROR"); #endif } morelines() { if ((int) sbrk(1024 * sizeof (line)) == -1) return (-1); endcore += 1024; return (0); } nonzero() { if (addr1 == zero) { notempty(); error("Nonzero address required@on this command"); } } notable(i) int i; { return (hush == 0 && !inglobal && i > value(REPORT)); } notempty() { if (dol == zero) error("No lines@in the buffer"); } netchHAD(cnt) int cnt; { netchange(lineDOL() - cnt); } netchange(i) register int i; { register char *cp; if (i > 0) notesgn = cp = "more "; else notesgn = cp = "fewer ", i = -i; if (inopen) { notecnt = i; notenam = ""; return; } if (!notable(i)) return; printf(mesg("%d %slines@in file after %s"), i, cp, Command); putNFL(); } putmark(addr) line *addr; { putmk1(addr, putline()); } putmk1(addr, n) register line *addr; int n; { register line *markp; register oldglobmk; oldglobmk = *addr & 1; *addr &= ~1; for (markp = (anymarks ? names : &names['z'-'a'+1]); markp <= &names['z'-'a'+1]; markp++) if (*markp == *addr) *markp = n; *addr = n | oldglobmk; } char * plural(i) long i; { return (i == 1 ? "" : "s"); } int qcount(); short vcntcol; qcolumn(lim, gp) register char *lim, *gp; { register int x; int (*OO)(); OO = Outchar; Outchar = qcount; vcntcol = 0; if (lim != NULL) x = lim[1], lim[1] = 0; pline(0); if (lim != NULL) lim[1] = x; if (gp) while (*gp) putchar(*gp++); Outchar = OO; return (vcntcol); } int qcount(c) int c; { if (c == '\t') { vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP); return; } vcntcol++; } reverse(a1, a2) register line *a1, *a2; { register line t; for (;;) { t = *--a2; if (a2 <= a1) return; *a2 = *a1; *a1++ = t; } } save(a1, a2) line *a1; register line *a2; { register int more; if (!FIXUNDO) return; #ifdef TRACE if (trace) vudump("before save"); #endif undkind = UNDNONE; undadot = dot; more = (a2 - a1 + 1) - (unddol - dol); while (more > (endcore - truedol)) if (morelines() < 0) error("Out of memory@saving lines for undo - try using ed"); if (more) (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1, (truedol - unddol)); unddol += more; truedol += more; copyw(dol + 1, a1, a2 - a1 + 1); undkind = UNDALL; unddel = a1 - 1; undap1 = a1; undap2 = a2 + 1; #ifdef TRACE if (trace) vudump("after save"); #endif } save12() { save(addr1, addr2); } saveall() { save(one, dol); } span() { return (addr2 - addr1 + 1); } sync() { chng = 0; tchng = 0; xchng = 0; } skipwh() { register int wh; wh = 0; while (iswhite(peekchar())) { wh++; ignchar(); } return (wh); } /*VARARGS2*/ smerror(seekpt, cp) #ifdef lint char *seekpt; #else int seekpt; #endif char *cp; { if (seekpt == 0) return; merror1(seekpt); if (inopen && CE) vclreol(); if (SO && SE) putpad(SO); lprintf(mesg(linebuf), cp); if (SO && SE) putpad(SE); } char * strend(cp) register char *cp; { while (*cp) cp++; return (cp); } strcLIN(dp) char *dp; { CP(linebuf, dp); } syserror() { dirtcnt = 0; putchar(' '); error("%s", strerror(errno)); } /* * 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); } char * vfindcol(i) int i; { register char *cp; register int (*OO)() = Outchar; Outchar = qcount; ignore(qcolumn(linebuf - 1, NOSTR)); for (cp = linebuf; *cp && vcntcol < i; cp++) putchar(*cp); if (cp != linebuf) cp--; Outchar = OO; return (cp); } char * vskipwh(cp) register char *cp; { while (iswhite(*cp) && cp[1]) cp++; return (cp); } char * vpastwh(cp) register char *cp; { while (iswhite(*cp)) cp++; return (cp); } whitecnt(cp) register char *cp; { register int i; i = 0; for (;;) switch (*cp++) { case '\t': i += value(TABSTOP) - i % value(TABSTOP); break; case ' ': i++; break; default: return (i); } } #ifdef lint Ignore(a) char *a; { a = a; } Ignorf(a) int (*a)(); { a = a; } #endif markit(addr) line *addr; { if (addr != dot && addr >= one && addr <= dol) markDOT(); } /* * The following code is defensive programming against a bug in the * pdp-11 overlay implementation. Sometimes it goes nuts and asks * for an overlay with some garbage number, which generates an emt * trap. This is a less than elegant solution, but it is somewhat * better than core dumping and losing your work, leaving your tty * in a weird state, etc. */ int _ovno; onemt() { int oovno; signal(SIGEMT, onemt); oovno = _ovno; /* 2 and 3 are valid on 11/40 type vi, so */ if (_ovno < 0 || _ovno > 3) _ovno = 0; error("emt trap, _ovno is %d @ - try again"); } /* * When a hangup occurs our actions are similar to a preserve * command. If the buffer has not been [Modified], then we do * nothing but remove the temporary files and exit. * Otherwise, we sync the temp file and then attempt a preserve. * If the preserve succeeds, we unlink our temp files. * If the preserve fails, we leave the temp files as they are * as they are a backup even without preservation if they * are not removed. */ onhup() { /* * USG tty driver can send multiple HUP's!! */ signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); if (chng == 0) { cleanup(1); exit(0); } if (setexit() == 0) { if (preserve()) { cleanup(1); exit(0); } } exit(1); } /* * An interrupt occurred. Drain any output which * is still in the output buffering pipeline. * Catch interrupts again. Unless we are in visual * reset the output state (out of -nl mode, e.g). * Then like a normal error (with the \n before Interrupt * suppressed in visual mode). */ onintr() { #ifndef CBREAK signal(SIGINT, onintr); #else signal(SIGINT, inopen ? vintr : onintr); #endif alarm(0); /* in case we were called from map */ draino(); if (!inopen) { pstop(); setlastchar('\n'); #ifdef CBREAK } #else } else vraw(); #endif error("\nInterrupt" + inopen); } /* * If we are interruptible, enable interrupts again. * In some critical sections we turn interrupts off, * but not very often. */ setrupt() { if (ruptible) { #ifndef CBREAK signal(SIGINT, onintr); #else signal(SIGINT, inopen ? vintr : onintr); #endif #ifdef SIGTSTP if (dosusp) signal(SIGTSTP, onsusp); #endif } } preserve() { #ifdef VMUNIX tflush(); #endif synctmp(); pid = fork(); if (pid < 0) return (0); if (pid == 0) { close(0); dup(tfile); execl(EXPRESERVE, "expreserve", (char *) 0); exit(1); } waitfor(); if (rpid == pid && status == 0) return (1); return (0); } #ifndef V6 exit(i) int i; { # ifdef TRACE if (trace) fclose(trace); # endif _exit(i); } #endif #ifdef SIGTSTP /* * We have just gotten a susp. Suspend and prepare to resume. */ onsusp() { ttymode f; int omask; struct winsize win; f = setty(normf); vnfl(); putpad(TE); flush(); (void) sigsetmask(0L); signal(SIGTSTP, SIG_DFL); kill(0, SIGTSTP); /* the pc stops here */ signal(SIGTSTP, onsusp); vcontin(0); setty(f); if (!inopen) error(0); else { if (ioctl(0, TIOCGWINSZ, &win) >= 0) if (win.ws_row != winsz.ws_row || win.ws_col != winsz.ws_col) winch(); if (vcnt < 0) { vcnt = -vcnt; if (state == VISUAL) vclear(); else if (state == CRTOPEN) vcnt = 0; } vdirty(0, LINES); vrepaint(cursor); } } #endif