diff options
Diffstat (limited to 'ex_subr.c')
-rw-r--r-- | ex_subr.c | 1153 |
1 files changed, 1153 insertions, 0 deletions
diff --git a/ex_subr.c b/ex_subr.c new file mode 100644 index 0000000..6f884aa --- /dev/null +++ b/ex_subr.c @@ -0,0 +1,1153 @@ +/* + * This code contains changes by + * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved. + * + * Conditions 1, 2, and 4 and the no-warranty notice below apply + * to these changes. + * + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +#ifdef DOSCCS +static char sccsid[] = "@(#)ex_subr.c 1.37 (gritter) 2/15/05"; +#endif +#endif + +/* from ex_subr.c 7.10.1 (2.11BSD) 1996/3/22 */ + +#include "ex.h" +#include "ex_re.h" +#include "ex_tty.h" +#include "ex_vis.h" + +static short lastsc; + +/* + * Random routines, in alphabetical order. + */ + +int +any(int c, register char *s) +{ + register int x; + + while (x = *s++) + if (x == c) + return (1); + return (0); +} + +int +backtab(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); +} + +void +change(void) +{ + + tchng++; + chng = tchng; + fixedzero = 0; +} + +/* + * Column returns the number of + * columns occupied by printing the + * characters through position cp of the + * current line. + */ +int +column(register char *cp) +{ + + if (cp == 0) + cp = &linebuf[LBSIZE - 2]; + return (qcolumn(cp, NULL)); +} + +int +lcolumn(register char *cp) +{ + return column(cp) - (lastsc - 1); +} + +/* + * Ignore a comment to the end of the line. + * This routine eats the trailing newline so don't call newline(). + */ +void +comment(void) +{ + register int c; + + do { + c = getchar(); + } while (c != '\n' && c != EOF); + if (c == EOF) + ungetchar(c); +} + +void +Copy(register char *to, register char *from, register int size) +{ + + if (size > 0) + do + *to++ = *from++; + while (--size > 0); +} + +void +copyw(register line *to, register line *from, register int size) +{ + + if (size > 0) + do + *to++ = *from++; + while (--size > 0); +} + +void +copywR(register line *to, register line *from, register int size) +{ + + while (--size >= 0) + to[size] = from[size]; +} + +int +ctlof(int c) +{ + + return (c == DELETE ? '?' : c | ('A' - 1)); +} + +void +dingdong(void) +{ + + if (VB) + putpad(VB); + else if (value(ERRORBELLS)) + putch('\207'); +} + +int +fixindent(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); +} + +void +filioerr(char *cp) +{ + register int oerrno = errno; + + lprintf("\"%s\"", cp); + errno = oerrno; + syserror(); +} + +char * +genindent(register int indent) +{ + register char *cp; + + for (cp = genbuf; indent >= value(TABSTOP); indent -= value(TABSTOP)) + *cp++ = '\t'; + for (; indent > 0; indent--) + *cp++ = ' '; + return (cp); +} + +void +getDOT(void) +{ + + getline(*dot); +} + +line * +getmark(register int c) +{ + register line *addr; + + for (addr = one; addr <= dol; addr++) + if (names[c - 'a'] == (*addr &~ 01)) { + return (addr); + } + return (0); +} + +int +getn(register char *cp) +{ + register int i = 0; + + while (isdigit(*cp&0377)) + i = i * 10 + *cp++ - '0'; + if (*cp) + return (0); + return (i); +} + +void +ignnEOF(void) +{ + register int c = getchar(); + + if (c == EOF) + ungetchar(c); + else if (c=='"') + comment(); +} + +int +is_white(int c) +{ + +#ifndef BIT8 + return (c == ' ' || c == '\t'); +#else + return (isspace(c&0377) && c != '\n' && c != '\r' + && c != '\f' && c != '\v'); +#endif +} + +int +junk(register int c) +{ + + if (c && !value(BEAUTIFY)) + return (0); +#ifndef BIT8 + if (c >= ' ' && c != DELETE) +#else + if (printable(c)) +#endif + return (0); + switch (c) { + + case '\t': + case '\n': + case '\f': + return (0); + + default: + return (1); + } +} + +void +killed(void) +{ + + killcnt(addr2 - addr1 + 1); +} + +void +killcnt(register int cnt) +{ + + if (inopen) { + notecnt = cnt; + notenam = notesgn = ""; + return; + } + if (!notable(cnt)) + return; + printf(catgets(catd, 1, 170, "%d lines"), cnt); + if (value(TERSE) == 0) { + printf(catgets(catd, 1, 171, " %c%s"), + Command[0] | ' ', Command + 1); + if (Command[strlen(Command) - 1] != 'e') + putchar('e'); + putchar('d'); + } + putNFL(); +} + +int +lineno(line *a) +{ + + return (a - zero); +} + +int +lineDOL(void) +{ + + return (lineno(dol)); +} + +int +lineDOT(void) +{ + + return (lineno(dot)); +} + +void +markDOT(void) +{ + + markpr(dot); +} + +void +markpr(line *which) +{ + + if ((inglobal == 0 || inopen) && which <= endcore) { + names['z'-'a'+1] = *which & ~01; + if (inopen) + ncols['z'-'a'+1] = cursor; + } +} + +int +markreg(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(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); +} + +void +merror1(intptr_t seekpt) +{ + +#ifdef VMUNIX + strcpy(linebuf, (char *)seekpt); +#else + lseek(erfile, (off_t) seekpt, SEEK_SET); + if (read(erfile, linebuf, 128) < 2) + CP(linebuf, "ERROR"); +#endif +} + +/*VARARGS2*/ +void +vmerror(char *seekpt, va_list ap) +{ + + register char *cp = linebuf; + + if (seekpt == 0) + return; + merror1((intptr_t)seekpt); + if (*cp == '\n') + putnl(), cp++; + if (inopen > 0 && CE) + vclreol(); + if (SO && SE) + putpad(SO); + vprintf(mesg(cp), ap); + if (SO && SE) + putpad(SE); +} + +void +merror(char *cp, ...) +{ + va_list ap; + + if (cp == NULL) + return; + va_start(ap, cp); + vmerror(cp, ap); + va_end(ap); +} + +int +morelines(void) +{ +#ifdef _SC_PAGESIZE + static long pg; + + if (pg == 0) { + pg = sysconf(_SC_PAGESIZE); + if (pg <= 0 || pg >= 65536) + pg = 4096; + pg /= sizeof (line); + } + if ((char *)sbrk(pg * sizeof (line)) == (char *)-1) + return (-1); + endcore += pg; + return (0); +#else /* !_SC_PAGESIZE */ + if (sbrk(1024 * sizeof (line)) == (char *)-1) + return (-1); + endcore += 1024; + return (0); +#endif /* !_SC_PAGESIZE */ +} + +void +nonzero(void) +{ + + if (addr1 == zero) { + notempty(); + error(catgets(catd, 1, 172, + "Nonzero address required@on this command")); + } +} + +int +notable(int i) +{ + + return (hush == 0 && !inglobal && i > value(REPORT)); +} + + +void +notempty(void) +{ + + if (dol == zero) + error(catgets(catd, 1, 173, "No lines@in the buffer")); +} + + +void +netchHAD(int cnt) +{ + + netchange(lineDOL() - cnt); +} + +void +netchange(register int i) +{ + register char *cp; + + if (i > 0) + notesgn = cp = catgets(catd, 1, 174, "more "); + else + notesgn = cp = catgets(catd, 1, 175, "fewer "), i = -i; + if (inopen) { + notecnt = i; + notenam = catgets(catd, 1, 176, ""); + return; + } + if (!notable(i)) + return; + printf(mesg(catgets(catd, 1, 177, "%d %slines@in file after %s")), + i, cp, Command); + putNFL(); +} + +/* + * Print an escape sequence corresponding to c. + */ +#ifdef BIT8 +int +printof(int c) +{ + char *nums = "01234567"; + int d; + +#ifdef MB + if (mb_cur_max > 1 && (c & INVBIT) == 0 && c & ~0177) { + char mb[MB_LEN_MAX]; + int i, n, x = EOF; + if ((n = wctomb(mb, c & TRIM)) <= 0) { + n = 1; + *mb = 0; + } + for (i = 0; i < n; i++) { + x = printof(mb[i] | INVBIT); + if (i+1 < n) + normchar(x); + } + return x; + } +#endif /* MB */ + c &= 0377; + if (c < 040 || c == DELETE) { + normchar('^'); + return (c == DELETE ? '?' : c | ('A' - 1)); + } + normchar('\\'); + normchar(nums[(c & ~077) >> 6]); + c &= 077; + d = c & 07; + if (c > d) + normchar(nums[(c - d) >> 3]); + else + normchar(nums[0]); + return nums[d]; +} +#endif + +void +putmark(line *addr) +{ + + putmk1(addr, putline()); +} + +void +putmk1(register line *addr, int n) +{ + register line *markp; + register int 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(long i) +{ + + return (i == 1 ? catgets(catd, 1, 178, "") + : catgets(catd, 1, 179, "s")); +} + +static short vcntcol; + +int +qcolumn(register char *lim, register char *gp) +{ + register int x = 0, n = 1; + int c, i; + int (*OO)(); + + OO = Outchar; + Outchar = qcount; + vcntcol = 0; + if (lim != NULL) { + if (lim < linebuf) { + lim = linebuf; + n = 0; + } else + n = skipright(linebuf, lim); + x = lim[n], lim[n] = 0; + } + pline(0); + if (lim != NULL) + lim[n] = x; + if (gp) + while (*gp) { + nextc(c, gp, i); + putchar(c); + gp += i; + } + Outchar = OO; + return (vcntcol); +} + +int +qcount(int c) +{ + if (c == '\t') { + vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP); + lastsc = 1; + return c; + } + /* + * Take account of filler characters inserted at the end of + * the visual line if a multi-column character does not fit. + */ + lastsc = colsc(c&TRIM&~MULTICOL); + while (vcntcol < WCOLS && vcntcol + lastsc - 1 >= WCOLS) + vcntcol++; + vcntcol += c & MULTICOL ? 1 : lastsc; + return c; +} + +void +reverse(register line *a1, register line *a2) +{ + register line t; + + for (;;) { + t = *--a2; + if (a2 <= a1) + return; + *a2 = *a1; + *a1++ = t; + } +} + +void +save(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(catgets(catd, 1, 180, + "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 +} + +void +save12(void) +{ + + save(addr1, addr2); +} + +void +saveall(void) +{ + + save(one, dol); +} + +int +span(void) +{ + + return (addr2 - addr1 + 1); +} + +void +synced(void) +{ + + chng = 0; + tchng = 0; + xchng = 0; +} + + +int +skipwh(void) +{ + register int wh; + + wh = 0; + while (is_white(peekchar())) { + wh++; + ignchar(); + } + return (wh); +} + +void +vsmerror(char *seekpt, va_list ap) +{ + + if (seekpt == 0) + return; + merror1((intptr_t)seekpt); + if (inopen && CE) + vclreol(); + if (SO && SE) + putpad(SO); + vlprintf(mesg(linebuf), ap); + if (SO && SE) + putpad(SE); +} + +void +smerror(char *seekpt, ...) +{ + va_list ap; + + if (seekpt == NULL) + return; + va_start(ap, seekpt); + vsmerror(seekpt, ap); + va_end(ap); +} + +char * +strend(register char *cp) +{ + + while (*cp) + cp++; + return (cp); +} + +void +strcLIN(char *dp) +{ + + CP(linebuf, dp); +} + +void +syserror(void) +{ + + 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 > TCOLUMNS, even if ts does not divide TCOLUMNS. + */ +int +tabcol(int col, int ts) +{ + int offset, result; + + if (col >= TCOLUMNS) { + offset = TCOLUMNS * (col/TCOLUMNS); + col -= offset; + } else + offset = 0; + result = col + ts - (col % ts) + offset; + return (result); +} + +char * +vfindcol(int i) +{ + register char *cp; + register int (*OO)() = Outchar; + int c, n = 0; + + Outchar = qcount; + ignore(qcolumn(linebuf - 1, NOSTR)); + for (cp = linebuf; *cp && vcntcol < i; cp += n) { + nextc(c, cp, n); + putchar(c); + } + if (cp != linebuf) + cp -= n; + Outchar = OO; + return (cp); +} + +char * +vskipwh(register char *cp) +{ + + while (is_white(*cp) && cp[1]) + cp++; + return (cp); +} + + +char * +vpastwh(register char *cp) +{ + + while (is_white(*cp)) + cp++; + return (cp); +} + +int +whitecnt(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); + } +} + +void +markit(line *addr) +{ + + if (addr != dot && addr >= one && addr <= dol) + markDOT(); +} + +#ifdef SIGEMT +/* + * 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; +void +onemt(int signum) +{ + int oovno; + + oovno = _ovno; + /* 2 and 3 are valid on 11/40 type vi, so */ + if (_ovno < 0 || _ovno > 3) + _ovno = 0; + error(catgets(catd, 1, 181, "emt trap, _ovno is %d @ - try again")); +} +#endif + +/* + * 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. + */ +void +onhup(int signum) +{ + + /* + * USG tty driver can send multiple HUP's!! + */ + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + if (chng == 0) { + cleanup(1); + exitex(0); + } + if (setexit() == 0) { + if (preserve()) { + cleanup(1); + exitex(0); + } + } + exitex(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). + */ +void +onintr(int signum) +{ + + alarm(0); /* in case we were called from map */ + draino(); + if (!inopen) { + pstop(); + setlastchar('\n'); + } + error(catgets(catd, 1, 182, "\nInterrupt") + inopen); +} + +/* + * If we are interruptible, enable interrupts again. + * In some critical sections we turn interrupts off, + * but not very often. + */ +void +setrupt(void) +{ + + if (ruptible) { + signal(SIGINT, inopen ? vintr : onintr); +#ifdef SIGTSTP + if (dosusp) + signal(SIGTSTP, onsusp); +#endif + } +} + +int +preserve(void) +{ + +#ifdef INCORB + tflush(); +#endif + synctmp(); + pid = fork(); + if (pid < 0) + return (0); + if (pid == 0) { + close(0); + dup(tfile); + execl(EXPRESERVE, "expreserve", (char *)0); + exitex(1); + } + waitfor(); + if (rpid == pid && status == 0) + return (1); + return (0); +} + +int +exitex(int i) +{ + +# ifdef TRACE + if (trace) + fclose(trace); +# endif + if (failed != 0 && i == 0) + i = failed; + _exit(i); + /*NOTREACHED*/ + return 0; +} + +#ifdef SIGTSTP +/* + * We have just gotten a susp. Suspend and prepare to resume. + */ +void +onsusp(int signum) +{ + struct termios f; + /* int omask; */ +#ifdef TIOCGWINSZ + struct winsize win; +#endif + sigset_t set; + + f = setty(normf); + vnfl(); + putpad(TE); + flush(); + + sigemptyset(&set); + sigprocmask(SIG_SETMASK, &set, NULL); + signal(SIGTSTP, SIG_DFL); + kill(0, SIGTSTP); + + /* the pc stops here */ + + signal(SIGTSTP, onsusp); + vcontin(0); + setty(f); + if (!inopen) + error(0); +#ifdef TIOCGWINSZ + else { + if (ioctl(0, TIOCGWINSZ, &win) >= 0) + if (win.ws_row != winsz.ws_row || + win.ws_col != winsz.ws_col) + onwinch(SIGWINCH); + if (vcnt < 0) { + vcnt = -vcnt; + if (state == VISUAL) + vclear(); + else if (state == CRTOPEN) + vcnt = 0; + } + vdirty(0, TLINES); + vrepaint(cursor); + } +#endif /* TIOCGWINSZ */ +} +#endif /* SIGTSTP */ + +/* + * For regular strcpy(), source and destination may not overlap. + */ +char * +movestr(char *s1, const char *s2) +{ + char *cp = s1; + + while (*s1++ = *s2++); + return cp; +} + +/* + * strcpy() checking the maximum size of s1, printing msg in case of overflow. + */ +char * +safecp(char *s1, const char *s2, size_t max, char *msg, ...) +{ + va_list ap; + char *cp = s1; + + while (max--) + if ((*s1++ = *s2++) == '\0') + return cp; + va_start(ap, msg); + verror(msg, ap); + va_end(ap); + exitex(0175); + /*NOTREACHED*/ + return NULL; +} + +/* + * strcat() checking the maximum size of s1, printing msg in case of overflow. + */ +char * +safecat(char *s1, const char *s2, size_t max, char *msg, ...) +{ + va_list ap; + char *cp = s1; + + while (max && *s1) + max--, s1++; + while (max--) + if ((*s1++ = *s2++) == '\0') + return cp; + va_start(ap, msg); + verror(msg, ap); + va_end(ap); + exitex(0175); + /*NOTREACHED*/ + return NULL; +} |