Subversion Repositories planix.SVN

Compare Revisions

Ignore whitespace Rev 98 → Rev 99

/ports/trunk/editors/exvi/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;
}
/ports/trunk/editors/exvi/ex_temp.c
0,0 → 1,771
/*
* 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_temp.c 1.24 (gritter) 11/24/04";
#endif
#endif
 
/* from ex_temp.c 7.5.1.1 (Berkeley) 8/12/86 */
 
#include "ex.h"
#include "ex_temp.h"
#include "ex_vis.h"
#include "ex_tty.h"
#include <sys/wait.h>
#include <time.h>
 
/*
* Editor temporary file routines.
* Very similar to those of ed, except uses 2 input buffers.
*/
#define READ 0
#define WRITE 1
 
/*
* Maximum number of attempts to create temporary file.
*/
#define ATTEMPTS 20
 
char *tfname;
char *rfname;
int havetmp;
int tfile = -1;
int rfile = -1;
 
void
fileinit(void)
{
register char *p;
struct stat stbuf;
register int i, j;
pid_t mypid = getpid();
char *tfend;
int attempts = 0;
 
CLOBBGRD(attempts);
if (tline == INCRMT * (HBLKS+2))
return;
cleanup(0);
if (tfile != -1)
close(tfile);
tline = INCRMT * (HBLKS+2);
blocks[0] = HBLKS;
blocks[1] = HBLKS+1;
blocks[2] = -1;
dirtcnt = 0;
iblock = -1;
iblock2 = -1;
oblock = -1;
tfname = realloc(tfname, strlen(svalue(DIRECTORY)) + 14);
CP(tfname, svalue(DIRECTORY));
if (stat(tfname, &stbuf)) {
dumbness:
if (setexit() == 0)
filioerr(tfname);
else
putNFL();
cleanup(1);
exitex(1);
}
if ((stbuf.st_mode & S_IFMT) != S_IFDIR) {
errno = ENOTDIR;
goto dumbness;
}
ichanged = 0;
ichang2 = 0;
#ifdef notdef /* GR */
ignore(strcat(tfname, "/ExXXXXX"));
for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10)
*--p = j % 10 | '0';
tfile = creat(tfname, 0600);
#else
ignore(strcat(tfname, "/ExXXXXXXXXXX"));
tfend = strend(tfname);
do {
for (p = tfend, i = 10, j = mypid + attempts;
i > 0; i--, j /= 10)
*--p = j % 10 | '0';
tfile = open(tfname, O_CREAT|O_EXCL|O_RDWR
#ifdef O_NOFOLLOW
|O_NOFOLLOW
#endif /* O_NOFOLLOW */
, 0600);
} while (tfile < 0 && attempts++ < ATTEMPTS);
#endif /* !notdef */
if (tfile < 0)
goto dumbness;
#ifdef INCORB
{
extern bloc stilinc; /* see below */
stilinc = 0;
}
#endif
havetmp = 1;
/* brk((char *)fendcore); */
}
 
void
cleanup(bool all)
{
if (all) {
putpad(TE);
flush();
}
if (havetmp)
unlink(tfname);
havetmp = 0;
if (all && rfile >= 0) {
unlink(rfname);
close(rfile);
rfile = -1;
}
}
 
void
getline(line tl)
{
register char *bp, *lp;
register bbloc nl;
 
lp = linebuf;
bp = getblock(tl, READ);
nl = nleft;
tl &= ~OFFMSK;
while (*lp++ = *bp++)
if (--nl == 0) {
bp = getblock(tl += INCRMT, READ);
nl = nleft;
}
}
 
line
putline(void)
{
register char *bp, *lp;
register bbloc nl;
line tl;
 
dirtcnt++;
lp = linebuf;
change();
tl = tline;
bp = getblock(tl, WRITE);
nl = nleft;
tl &= ~OFFMSK;
while (*bp = *lp++) {
if (*bp++ == '\n') {
*--bp = 0;
linebp = lp;
break;
}
if (--nl == 0) {
bp = getblock(tl += INCRMT, WRITE);
nl = nleft;
}
}
tl = tline;
tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776;
return (tl);
}
 
char *
getblock(line atl, int iof)
{
register bbloc bno, off;
bno = (atl >> OFFBTS) & BLKMSK;
off = (atl << SHFT) & LBTMSK;
if (bno >= NMBLKS)
error(catgets(catd, 1, 183, " Tmp file too large"));
nleft = BUFSIZ - off;
if (bno == iblock) {
ichanged |= iof;
hitin2 = 0;
return (ibuff + off);
}
if (bno == iblock2) {
ichang2 |= iof;
hitin2 = 1;
return (ibuff2 + off);
}
if (bno == oblock)
return (obuff + off);
if (iof == READ) {
if (hitin2 == 0) {
if (ichang2) {
blkio(iblock2, ibuff2, (ssize_t(*)())write);
}
ichang2 = 0;
iblock2 = bno;
blkio(bno, ibuff2, (ssize_t(*)())read);
hitin2 = 1;
return (ibuff2 + off);
}
hitin2 = 0;
if (ichanged) {
blkio(iblock, ibuff, (ssize_t(*)())write);
}
ichanged = 0;
iblock = bno;
blkio(bno, ibuff, (ssize_t(*)())read);
return (ibuff + off);
}
if (oblock >= 0) {
blkio(oblock, obuff, (ssize_t(*)())write);
}
oblock = bno;
return (obuff + off);
}
 
#ifdef INCORB
char incorb[INCORB+1][BUFSIZ];
#define pagrnd(a) ((char *)(((size_t)a)&~(BUFSIZ-1)))
bloc stilinc; /* up to here not written yet */
#endif
 
void
blkio(bloc b, char *buf, ssize_t (*iofcn)(int, void *, size_t))
{
 
#ifdef INCORB
if (b < INCORB) {
if (iofcn == (ssize_t(*)())read) {
copy(buf, pagrnd(incorb[b+1]), (size_t) BUFSIZ);
return;
}
copy(pagrnd(incorb[b+1]), buf, (size_t) BUFSIZ);
if (laste) {
if (b >= stilinc)
stilinc = b + 1;
return;
}
} else if (stilinc)
tflush();
#endif
lseek(tfile, (off_t) ((b & BLKMSK) * BUFSIZ), SEEK_SET);
if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
filioerr(tfname);
}
 
#ifdef INCORB
void
tlaste(void)
{
 
if (stilinc)
dirtcnt = 0;
}
 
void
tflush(void)
{
bbloc i = stilinc;
stilinc = 0;
lseek(tfile, (off_t) 0, SEEK_SET);
if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ))
filioerr(tfname);
}
#endif
 
/*
* Synchronize the state of the temporary file in case
* a crash occurs.
*/
void
synctmp(void)
{
register bbloc cnt;
register line *a;
register bloc *bp, *up;
 
#ifdef INCORB
if (stilinc)
return;
#endif
if (dol == zero)
return;
if (ichanged)
blkio(iblock, ibuff, (ssize_t(*)())write);
ichanged = 0;
if (ichang2)
blkio(iblock2, ibuff2, (ssize_t(*)())write);
ichang2 = 0;
if (oblock != -1)
blkio(oblock, obuff, (ssize_t(*)())write);
time(&H.Time);
uid = getuid();
*zero = (line) H.Time;
up = blocks + LBLKS;
for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) {
if (bp >= up)
error(catgets(catd, 1, 184, " Tmp file too large"));
if (*bp < 0) {
tline = (tline + OFFMSK) &~ OFFMSK;
*bp = ((tline >> OFFBTS) & BLKMSK);
if (*bp > NMBLKS)
error(catgets(catd, 1, 185,
" Tmp file too large"));
tline += INCRMT;
oblock = *bp + 1;
bp[1] = -1;
}
lseek(tfile, (off_t) ((*bp & BLKMSK) * BUFSIZ), SEEK_SET);
cnt = ((dol - a) + 2) * sizeof (line);
if (cnt > BUFSIZ)
cnt = BUFSIZ;
if (write(tfile, (char *) a, cnt) != cnt) {
oops:
*zero = 0;
filioerr(tfname);
}
*zero = 0;
}
flines = lineDOL();
lseek(tfile, (off_t) 0, SEEK_SET);
if (write(tfile, (char *) &H, sizeof H) != sizeof H)
goto oops;
#ifdef notdef
/*
* This will insure that exrecover gets as much
* back after a crash as is absolutely possible,
* but can result in pregnant pauses between commands
* when the TSYNC call is made, so...
*/
fsync(tfile);
#endif
}
 
void
TSYNC(void)
{
 
if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */
#ifdef INCORB
if (stilinc)
tflush();
#endif
dirtcnt = 0;
synctmp();
}
}
 
/*
* Named buffer routines.
* These are implemented differently than the main buffer.
* Each named buffer has a chain of blocks in the register file.
* Each block contains roughly 508 chars of text,
* and a previous and next block number. We also have information
* about which blocks came from deletes of multiple partial lines,
* e.g. deleting a sentence or a LISP object.
*
* We maintain a free map for the temp file. To free the blocks
* in a register we must read the blocks to find how they are chained
* together.
*
* BUG: The default savind of deleted lines in numbered
* buffers may be rather inefficient; it hasn't been profiled.
*/
struct strreg {
short rg_flags;
short rg_nleft;
short rg_first;
short rg_last;
} strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp;
 
struct rbuf {
short rb_prev;
short rb_next;
char rb_text[BUFSIZ - 2 * sizeof (short)];
} *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf;
#ifdef VMUNIX
#ifdef LARGEF
short rused[4096];
#else /* !LARGEF */
short rused[256];
#endif /* !LARGEF */
#else /* !VMUNIX */
short rused[32];
#endif /* !VMUNIX */
short rnleft;
short rblock;
short rnext;
char *rbufcp;
 
void
regio(short b, ssize_t (*iofcn)(int, void *, size_t))
{
register char *p;
char *rfend;
int attempts = 0;
register int i, j;
pid_t mypid = getpid();
 
if (rfile == -1) {
rfname = realloc(rfname, strlen(svalue(DIRECTORY)) + 14);
CP(rfname, tfname);
rfend = strend(rfname);
#ifdef notdef /* GR */
*(rfend - 7) = 'R';
#else
*(rfend - 12) = 'R';
#endif
do {
for (p = rfend, i = 10, j = mypid + attempts;
i > 0; i--, j /= 10)
*--p = j % 10 | '0';
rfile = open(rfname, O_CREAT|O_EXCL|O_RDWR
#ifdef O_NOFOLLOW
|O_NOFOLLOW
#endif /* O_NOFOLLOW */
, 0600);
} while (rfile < 0 && attempts++ < ATTEMPTS);
if (rfile < 0)
oops:
filioerr(rfname);
}
lseek(rfile, (off_t) ((b & BLKMSK) * BUFSIZ), SEEK_SET);
if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ)
goto oops;
rblock = b;
}
 
int
REGblk(void)
{
register int i, j, m;
 
for (i = 0; i < sizeof rused / sizeof rused[0]; i++) {
m = (rused[i] ^ 0177777) & 0177777;
if (i == 0)
m &= ~1;
if (m != 0) {
j = 0;
while ((m & 1) == 0)
j++, m >>= 1;
rused[i] |= (1 << j);
#ifdef RDEBUG
printf("allocating block %d\n", i * 16 + j);
#endif
return (i * 16 + j);
}
}
error(catgets(catd, 1, 186, "Out of register space (ugh)"));
/*NOTREACHED*/
return 0;
}
 
struct strreg *
mapreg(register int c)
{
 
if (isupper(c))
c = tolower(c);
return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
}
 
void
KILLreg(register int c)
{
register struct strreg *sp;
 
rbuf = &KILLrbuf;
sp = mapreg(c);
rblock = sp->rg_first;
sp->rg_first = sp->rg_last = 0;
sp->rg_flags = sp->rg_nleft = 0;
while (rblock != 0) {
#ifdef RDEBUG
printf("freeing block %d\n", rblock);
#endif
rused[rblock / 16] &= ~(1 << (rblock % 16));
regio(rblock, (ssize_t (*)(int, void *, size_t))shread);
rblock = rbuf->rb_next;
}
}
 
ssize_t
shread(void)
{
struct front { short a; short b; };
 
if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front))
return (sizeof (struct rbuf));
return (0);
}
 
int getREG();
 
void
putreg(int c)
{
register line *odot = dot;
register line *odol = dol;
register int cnt;
 
deletenone();
appendnone();
rbuf = &putrbuf;
rnleft = 0;
rblock = 0;
rnext = mapreg(c)->rg_first;
if (rnext == 0) {
if (inopen) {
splitw++;
vclean();
vgoto(WECHO, 0);
}
vreg = -1;
error(catgets(catd, 1, 187, "Nothing in register %c"), c);
}
if (inopen && partreg(c)) {
if (!FIXUNDO) {
splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
error(catgets(catd, 1, 188,
"Can't put partial line inside macro"));
}
squish();
addr1 = addr2 = dol;
}
cnt = append(getREG, addr2);
if (inopen && partreg(c)) {
unddol = dol;
dol = odol;
dot = odot;
pragged(0);
}
killcnt(cnt);
notecnt = cnt;
}
 
int
partreg(int c)
{
 
return (mapreg(c)->rg_flags);
}
 
void
notpart(register int c)
{
 
if (c)
mapreg(c)->rg_flags = 0;
}
 
int
getREG(void)
{
register char *lp = linebuf;
register int c;
 
for (;;) {
if (rnleft == 0) {
if (rnext == 0)
return (EOF);
regio(rnext, read);
rnext = rbuf->rb_next;
rbufcp = rbuf->rb_text;
rnleft = sizeof rbuf->rb_text;
}
c = *rbufcp;
if (c == 0)
return (EOF);
rbufcp++, --rnleft;
if (c == '\n') {
*lp++ = 0;
return (0);
}
*lp++ = c;
}
}
 
void
YANKreg(register int c)
{
register line *addr;
register struct strreg *sp;
char savelb[LBSIZE];
 
if (isdigit(c))
kshift();
if (islower(c))
KILLreg(c);
strp = sp = mapreg(c);
sp->rg_flags = inopen && cursor && wcursor;
rbuf = &YANKrbuf;
if (sp->rg_last) {
regio(sp->rg_last, read);
rnleft = sp->rg_nleft;
rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
} else {
rblock = 0;
rnleft = 0;
}
CP(savelb,linebuf);
for (addr = addr1; addr <= addr2; addr++) {
getline(*addr);
if (sp->rg_flags) {
if (addr == addr2)
*wcursor = 0;
if (addr == addr1)
strcpy(linebuf, cursor);
}
YANKline();
}
rbflush();
killed();
CP(linebuf,savelb);
}
 
void
kshift(void)
{
register int i;
 
KILLreg('9');
for (i = '8'; i >= '0'; i--)
copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
}
 
void
YANKline(void)
{
register char *lp = linebuf;
register struct rbuf *rp = rbuf;
register int c;
 
do {
c = *lp++;
if (c == 0)
c = '\n';
if (rnleft == 0) {
rp->rb_next = REGblk();
rbflush();
rblock = rp->rb_next;
rp->rb_next = 0;
rp->rb_prev = rblock;
rnleft = sizeof rp->rb_text;
rbufcp = rp->rb_text;
}
*rbufcp++ = c;
--rnleft;
} while (c != '\n');
if (rnleft)
*rbufcp = 0;
}
 
void
rbflush(void)
{
register struct strreg *sp = strp;
 
if (rblock == 0)
return;
regio(rblock, (ssize_t (*)(int, void *, size_t))write);
if (sp->rg_first == 0)
sp->rg_first = rblock;
sp->rg_last = rblock;
sp->rg_nleft = rnleft;
}
 
/* Register c to char buffer buf of size buflen */
void
regbuf(char c, char *buf, int buflen)
{
register char *p, *lp;
 
rbuf = &regrbuf;
rnleft = 0;
rblock = 0;
rnext = mapreg(c)->rg_first;
if (rnext==0) {
*buf = 0;
error(catgets(catd, 1, 189, "Nothing in register %c"),c);
}
p = buf;
while (getREG()==0) {
for (lp=linebuf; *lp;) {
if (p >= &buf[buflen])
error(catgets(catd, 1, 190,
"Register too long@to fit in memory"));
*p++ = *lp++;
}
*p++ = '\n';
}
if (partreg(c)) p--;
*p = '\0';
getDOT();
}
/ports/trunk/editors/exvi/ex_tty.c
0,0 → 1,407
/*
* 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_tty.c 1.29 (gritter) 2/17/05";
#endif
#endif
 
/* from ex_tty.c 7.10.1 (2.11BSD GTE) 12/9/94 */
 
#include "ex.h"
#include "ex_tty.h"
 
int ATTN = DELETE;
 
/*
* Terminal type initialization routines,
* and calculation of flags at entry or after
* a shell escape which may change them.
*/
/* short ospeed = -1; mjm: def also in tputs.c of termcap.a */
 
void
gettmode(void)
{
speed_t pospeed;
 
if (tcgetattr(1, &tty) < 0) {
ospeed = B0;
return;
}
pospeed = cfgetospeed(&tty);
if (ospeed != pospeed)
value(SLOWOPEN) = pospeed < B1200;
ospeed = pospeed;
normf = tty;
#if defined (UCVISUAL) && defined (IUCLC)
UPPERCASE = (tty.c_iflag & IUCLC) != 0;
#endif
#if defined (TAB3)
GT = (tty.c_oflag & TABDLY) != TAB3 && !XT;
#elif defined (XTABS)
GT = (tty.c_oflag & TABDLY) != XTABS && !XT;
#else
GT = !XT;
#endif /* !TAB3, XTABS */
/*
* Tabs and multi-column characters do not combine properly
* unless vi performs a look-ahead on the current line. Just
* do not use them for now.
*/
if (mb_cur_max > 1)
GT = 0;
NONL = (tty.c_oflag & ONLCR) == 0;
ATTN = tty.c_cc[VINTR];
}
 
char *xPC;
char **sstrs[] = {
&AL, &BC, &BT, &CD, &CE, &CL, &CM, &xCR, &xCS, &DC, &DL, &DM, &DO,
&ED, &EI, &F0, &F1, &F2, &F3, &F4, &F5, &F6, &F7, &F8, &F9,
&HO, &IC, &IM, &IP, &KD, &KE, &KH, &KL, &KR, &KS, &KU, &LL, &ND, &xNL,
&xPC, &RC, &SC, &SE, &SF, &SO, &SR, &TA, &TE, &TI, &UP, &VB, &VS, &VE,
&AL_PARM, &DL_PARM, &UP_PARM, &DOWN_PARM, &LEFT_PARM, &RIGHT_PARM
};
bool *sflags[] = {
&AM, &BS, &DA, &DB, &EO, &HC,
#ifdef UCVISUAL
&xHZ,
#endif
&IN, &MI, &NC, &NS, &OS, &UL,
&XB, &XN, &XT, &XX
};
char **fkeys[10] = {
&F0, &F1, &F2, &F3, &F4, &F5, &F6, &F7, &F8, &F9
};
void
setterm(char *type)
{
register int unknown;
char ltcbuf[TCBUFSIZE];
 
if (type[0] == 0)
type = "xx";
unknown = 0;
putpad(TE);
if (tgetent(ltcbuf, type) != 1) {
unknown++;
CP(ltcbuf, "xx|dumb:");
}
gettmode(); /* must call gettmode() before setsize(). GR */
setsize();
aoftspace = tspace;
zap();
/*
* Initialize keypad arrow keys.
*/
addmac1(KU, "k", "up", arrows, 1);
addmac1(KD, "j", "down", arrows, 1);
addmac1(KL, "h", "left", arrows, 1);
addmac1(KR, "l", "right", arrows, 1);
addmac1(KH, "H", "home", arrows, 1);
 
/*
* Handle funny termcap capabilities
*/
if (xCS && SC && RC) {
if (AL==NULL) AL="";
if (DL==NULL) DL="";
}
if (AL_PARM && AL==NULL) AL="";
if (DL_PARM && DL==NULL) DL="";
if (IC && IM==NULL) IM="";
if (IC && EI==NULL) EI="";
if (!GT) BT=NULL; /* If we can't tab, we can't backtab either */
 
#ifdef TIOCLGET
#define HAS_JOB_CONTROL
#endif
#ifdef _SC_JOB_CONTROL
#define HAS_JOB_CONTROL
#endif
#ifdef HAS_JOB_CONTROL
/*
* 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 */;
 
if (sysconf(_SC_JOB_CONTROL) != -1)
{
/*
* If a system supports job control but no job
* control shell is used, only one method of
* detection remains: Our session id equals our
* process group id. Any job control shell would
* have created at least one new process group.
* But as the VSUSP key may be active, we have
* to override arrow keys either.
*/
#ifndef _CRAY /* getsid() is a bad syscall on UNICOS */
if (getsid(0) != getpgid(0))
#endif /* !_CRAY */
ldisc = 2; /* value of NTTYDISC */
sc[0] = tty.c_cc[VSUSP];
sc[1] = 0;
if (tty.c_cc[VSUSP] == CTRL('z')) {
for (i=0; i<=4; i++)
if (arrows[i].cap &&
arrows[i].cap[0] == CTRL('z'))
addmac(sc, NULL, NULL, arrows);
} else if (sc[0]
#ifdef _PC_VDISABLE
&& sc[0] != fpathconf(1, _PC_VDISABLE)
#endif
)
addmac(sc, "\32", "susp", arrows);
}
}
#endif /* HAS_JOB_CONTROL */
 
if (CM != 0) {
if (tgoto(CM, 2, 2)[0] == 'O') /* OOPS */
CA = 0, CM = 0;
else
CA = 1, costCM = cost(tgoto(CM, 8, 10));
} else {
CA = 0, CM = 0;
}
costSR = cost(SR);
costAL = cost(AL);
costDP = cost(tgoto(DOWN_PARM, 10, 10));
costLP = cost(tgoto(LEFT_PARM, 10, 10));
costRP = cost(tgoto(RIGHT_PARM, 10, 10));
PC = xPC ? xPC[0] : 0;
aoftspace = tspace;
safecp(ttylongname, gettlongname(ltcbuf, type), sizeof ttylongname,
"Terminal name too long");
/* proper strings to change tty type */
termreset();
gettmode();
value(REDRAW) = AL && DL;
value(OPTIMIZE) = !CA && !GT;
if (ospeed == B1200 && !value(REDRAW))
value(SLOWOPEN) = 1; /* see also gettmode above */
if (unknown)
serror(catgets(catd, 1, 191,
"%s: Unknown terminal type"), type);
}
 
void
setsize(void)
{
register int l, i;
#ifdef TIOCGWINSZ
struct winsize win;
#endif
 
char *e;
 
#ifdef TIOCGWINSZ
i = ioctl(0, TIOCGWINSZ, &win);
#endif
TLINES = TCOLUMNS = 0;
e = getenv("COLUMNS");
if (e != NULL && *e != '\0')
TCOLUMNS = atoi(e);
if (TCOLUMNS <= 0) {
#ifdef TIOCGWINSZ
if (i >= 0 && win.ws_col != 0)
TCOLUMNS = winsz.ws_col = win.ws_col;
else
#endif
TCOLUMNS = tgetnum("co");
}
e = getenv("LINES");
if (e != NULL && *e != '\0')
TLINES = atoi(e);
if (TLINES <= 0) {
#ifdef TIOCGWINSZ
if (i >= 0 && win.ws_row != 0)
TLINES = winsz.ws_row = win.ws_row;
else
#endif
TLINES = tgetnum("li");
}
i = TLINES;
if (TLINES <= 5)
TLINES = 24;
if (TLINES > TUBELINES)
TLINES = TUBELINES;
l = TLINES;
if (ospeed < B1200)
l = 9; /* including the message line at the bottom */
else if (ospeed < B2400)
l = 17;
if (l > TLINES)
l = TLINES;
if (TCOLUMNS <= 4)
TCOLUMNS = 1000;
options[WINDOW].ovalue = options[WINDOW].odefault = l - 1;
if (defwind) {
options[WINDOW].ovalue = defwind;
l = defwind + 1;
}
options[SCROLL].ovalue = options[SCROLL].odefault = HC ? 11 : ((l-1) / 2);
if (i <= 0)
TLINES = 2;
}
 
void
zap(void)
{
register char *namp;
register bool **fp;
register char ***sp;
int flag;
char *string;
 
#ifndef UCVISUAL
namp = "ambsdadbeohcinmincnsosulxbxnxtxx";
#else
namp = "ambsdadbeohchzinmincnsosulxbxnxtxx";
#endif
fp = sflags;
do {
flag = tgetflag(namp);
*(*fp++) = flag;
namp += 2;
} while (*namp);
namp = "albcbtcdceclcmcrcsdcdldmdoedeik0k1k2k3k4k5k6k7k8k9hoicimipkdkekhklkrkskullndnlpcrcscsesfsosrtatetiupvbvsveALDLUPDOLERI";
sp = sstrs;
do {
string = tgetstr(namp, &aoftspace);
*(*sp++) = string;
namp += 2;
} while (*namp);
}
 
char *
gettlongname(register char *bp, char *def)
{
register char *cp;
 
while (*bp && *bp != ':' && *bp != '|')
bp++;
if (*bp == '|') {
bp++;
cp = bp;
while (*cp && *cp != ':' && *cp != '|')
cp++;
*cp = 0;
return (bp);
}
return (def);
}
 
char *
fkey(int i)
{
if (0 <= i && i <= 9)
return(*fkeys[i]);
else
return(NOSTR);
}
 
/*
* cost figures out how much (in characters) it costs to send the string
* str to the terminal. It takes into account padding information, as
* much as it can, for a typical case. (Right now the typical case assumes
* the number of lines affected is the size of the screen, since this is
* mainly used to decide if AL or SR is better, and this always happens
* at the top of the screen. We assume cursor motion (CM) has little
* padding, if any, required, so that case, which is really more important
* than AL vs SR, won't be really affected.)
*/
static int costnum;
int
cost(char *str)
{
if (str == NULL || *str=='O') /* OOPS */
return 10000; /* infinity */
costnum = 0;
tputs(str, TLINES, countnum);
return costnum;
}
 
/*ARGSUSED*/
int
countnum(int ch)
{
costnum++;
return ch;
}
/ports/trunk/editors/exvi/ex_tune.h
0,0 → 1,225
/*
* 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.
*
* from ex_tune.h 7.8.1 (2.11BSD) 1996/10/23
*
* @(#)ex_tune.h 1.12 (gritter) 12/1/04
*/
 
/*
* Note: the parameters that are actually tuneable have been moved to
* config.h. Do not make changes here unless you know what you are
* doing! GR
*/
 
/*
* Definitions of editor parameters and limits
*/
 
/*
* Pathnames (will be predefined in Makefile).
*/
#ifndef EXRECOVER
#define EXRECOVER "/usr/sbin/exrecover"
#endif
#ifndef EXPRESERVE
#define EXPRESERVE "/usr/sbin/expreserve"
#endif
#ifndef VMUNIX
#ifndef EXSTRINGS
#define EXSTRINGS "/usr/share/misc/exstrings"
#endif
#endif
 
/*
* If your system believes that tabs expand to a width other than
* 8 then your makefile should cc with -DTABS=whatever, otherwise we use 8.
*/
#ifndef TABS
#define TABS 8
#endif
 
/*
* Maximums
*
* The definition of LBSIZE should be the same as BUFSIZ (512 usually).
* Most other definitions are quite generous.
*/
/* FNSIZE is also defined in expreserve.c */
#ifdef _POSIX_PATH_MAX
#define FNSIZE _POSIX_PATH_MAX
#else
#define FNSIZE 128 /* File name size */
#endif
#ifdef VMUNIX
#define LBSIZE BUFSIZ /* Line buffer size */
#ifndef ESIZE /* see config.h */
#define ESIZE 512 /* Regular expression buffer size */
#endif
#define CRSIZE BUFSIZ /* Crypt buffer size */
#else /* !VMUNIX */
#ifdef u370
#define LBSIZE 4096
#ifndef ESIZE /* see config.h */
#define ESIZE 512
#endif
#define CRSIZE 4096
#else
#define LBSIZE 512 /* Line length */
#ifndef ESIZE /* see config.h */
#define ESIZE 128 /* Size of compiled re */
#endif
#define CRSIZE 512
#endif
#endif
#define NBRA 9 /* Number of re \( \) pairs */
#define GBSIZE 256 /* Buffer size */
#define UXBSIZE 128 /* Unix command buffer size */
#define VBSIZE 128 /* Partial line max size in visual */
/* LBLKS is also defined in expreserve.c */
#ifndef VMUNIX
#define LBLKS 125 /* Line pointer blocks in temp file */
#define HBLKS 1 /* struct header fits in BUFSIZ*HBLKS */
#else /* VMUNIX */
#ifdef LARGEF
#define LBLKS 20000
#else /* !LARGEF */
#define LBLKS 900
#endif /* !LARGEF */
#define HBLKS (1 + (FNSIZE + LBLKS * sizeof(bloc)) / BUFSIZ)
#endif /* VMUNIX */
#define MAXDIRT 12 /* Max dirtcnt before sync tfile */
 
/*
* Size of in-core buffers for temporary file. Since this is
* sizeof (char) * (INCORB + 1) * BUFSIZ, it should not be too
* large.
*
* If not defined, no in-core buffers are used.
*/
#ifdef VMUNIX
#if (BUFSIZ - 0) <= 16384
#define INCORB (65536/BUFSIZ)
#else /* Huge-memory systems. */
#define INCORB 4
#endif /* Huge-memory systems. */
#endif /* VMUNIX */
 
/*
* Except on VMUNIX, these are a ridiculously small due to the
* lousy arglist processing implementation which fixes core
* proportional to them. Argv (and hence NARGS) is really unnecessary,
* and argument character space not needed except when
* arguments exist. Argument lists should be saved before the "zero"
* of the incore line information and could then
* be reasonably large.
*/
#undef NCARGS
#ifndef VMUNIX
#define NARGS 100 /* Maximum number of names in "next" */
#define NCARGS LBSIZE /* Maximum arglist chars in "next" */
#else
#define NCARGS 5120
#define NARGS (NCARGS/6)
#endif
 
/*
* Output column (and line) are set to this value on cursor addressible
* terminals when we lose track of the cursor to force cursor
* addressing to occur.
*/
#define UKCOL -20 /* Prototype unknown column */
 
/*
* Attention is the interrupt character (normally 0177 -- delete).
* Quit is the quit signal (normally FS -- control-\) and quits open/visual.
*/
extern int ATTN;
#define QUIT ('\\' & 037)
 
#define LRGINT INT_MAX /* largest normal length positive integer */
 
#ifdef LONG_BIT
#if (LONG_BIT > 32)
#define MAXOCT 22 /* Maximum octal digits in a long */
#define BIG 10000000000000000000UL /* largest power of 10 < uns. long */
#define MAXDIGS 20 /* number of digits in BIG */
#else /* LONG_BIT <= 32 */
#define MAXOCT 11 /* Maximum octal digits in a long */
#define BIG 1000000000UL /* largest power of 10 < unsigned long */
#define MAXDIGS 10 /* number of digits in BIG */
#endif /* LONG_BIT <= 32 */
#else /* !LONG_BIT */
#define MAXOCT 11 /* Maximum octal digits in a long */
#define BIG 1000000000 /* largest power of 10 < unsigned long */
#define MAXDIGS 10 /* number of digits in BIG */
#endif /* !LONG_BIT */
/ports/trunk/editors/exvi/ex_v.c
0,0 → 1,527
/*
* 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_v.c 1.17 (gritter) 11/27/04";
#endif
#endif
 
/* from ex_v.c 7.8.1 (2.11BSD GTE) 12/9/94 */
 
#include "ex.h"
#include "ex_re.h"
#include "ex_tty.h"
#include "ex_vis.h"
 
/*
* Entry points to open and visual from command mode processor.
* The open/visual code breaks down roughly as follows:
*
* ex_v.c entry points, checking of terminal characteristics
*
* ex_vadj.c logical screen control, use of intelligent operations
* insert/delete line and coordination with screen image;
* updating of screen after changes.
*
* ex_vget.c input of single keys and reading of input lines
* from the echo area, handling of memory for repeated
* commands and small saved texts from inserts and partline
* deletes, notification of multi line changes in the echo
* area.
*
* ex_vmain.c main command decoding, some command processing.
*
* ex_voperate.c decoding of operator/operand sequences and
* contextual scans, implementation of word motions.
*
* ex_vops.c major operator interfaces, undos, motions, deletes,
* changes, opening new lines, shifts, replacements and yanks
* coordinating logical and physical changes.
*
* ex_vops2.c subroutines for operator interfaces in ex_vops.c,
* insert mode, read input line processing at lowest level.
*
* ex_vops3.c structured motion definitions of ( ) { } and [ ] operators,
* indent for lisp routines, () and {} balancing.
*
* ex_vput.c output routines, clearing, physical mapping of logical cursor
* positioning, cursor motions, handling of insert character
* and delete character functions of intelligent and unintelligent
* terminals, visual mode tracing routines (for debugging),
* control of screen image and its updating.
*
* ex_vwind.c window level control of display, forward and backward rolls,
* absolute motions, contextual displays, line depth determination
*/
 
JMP_BUF venv;
 
/*
* Enter open mode
*/
#ifdef u370
cell atube[TUBESIZE+LBSIZE];
#endif
void
oop(void)
{
register char *ic;
#ifndef u370
cell atube[TUBESIZE + LBSIZE];
#endif
struct termios f; /* mjm: was register */
int resize;
 
resize = SETJMP(venv);
if (resize) {
setsize();
initev = (char *)0;
inopen = 0;
addr1 = addr2 = dot;
}
#ifdef SIGWINCH
signal(SIGWINCH, onwinch);
#endif
ovbeg();
if (peekchar() == '/') {
ignore(compile(getchar(), 1));
savere(&scanre);
if (execute(0, dot) == 0)
error(catgets(catd, 1, 207,
"Fail|Pattern not found on addressed line"));
ic = loc1;
if (ic > linebuf && *ic == 0)
ic--;
} else {
getDOT();
ic = vskipwh(linebuf);
}
newline();
 
/*
* If overstrike then have to HARDOPEN
* else if can move cursor up off current line can use CRTOPEN (~~vi1)
* otherwise (ugh) have to use ONEOPEN (like adm3)
*/
if (OS && !EO)
bastate = HARDOPEN;
else if (CA || UP)
bastate = CRTOPEN;
else
bastate = ONEOPEN;
setwind();
 
/*
* To avoid bombing on glass-crt's when the line is too long
* pretend that such terminals are 160 columns wide.
* If a line is too wide for display, we will dynamically
* switch to hardcopy open mode.
*/
if (state != CRTOPEN)
WCOLS = TUBECOLS;
if (!inglobal)
savevis();
vok(atube);
if (state != CRTOPEN)
TCOLUMNS = WCOLS;
Outchar = vputchar;
f = ostart();
if (state == CRTOPEN) {
if (outcol == UKCOL)
outcol = 0;
vmoveitup(1, 1);
} else
outline = destline = WBOT;
vshow(dot, NOLINE);
vnline(ic);
vmain();
if (state != CRTOPEN)
vclean();
Command = "open";
ovend(f);
#ifdef SIGWINCH
signal(SIGWINCH, SIG_DFL);
#endif
}
 
void
ovbeg(void)
{
 
if (!value(OPEN))
error(catgets(catd, 1, 208,
"Can't use open/visual unless open option is set"));
if (inopen)
error(catgets(catd, 1, 209,
"Recursive open/visual not allowed"));
Vlines = lineDOL();
fixzero();
setdot();
pastwh();
dot = addr2;
}
 
void
ovend(struct termios f)
{
 
splitw++;
vgoto(WECHO, 0);
vclreol();
vgoto(WECHO, 0);
holdcm = 0;
splitw = 0;
ostop(f);
setoutt();
undvis();
TCOLUMNS = OCOLUMNS;
inopen = 0;
flusho();
netchHAD(Vlines);
}
 
/*
* Enter visual mode
*/
void
vop(void)
{
register int c;
#ifndef u370
cell atube[TUBESIZE + LBSIZE];
#endif
struct termios f; /* mjm: was register */
int resize;
 
if (!CA && UP == NOSTR) {
if (initev) {
toopen:
merror(catgets(catd, 1, 210, "[Using open mode]"));
putNFL();
oop();
return;
}
error(catgets(catd, 1, 211,
"Visual needs addressible cursor or upline capability"));
}
if (OS && !EO) {
if (initev)
goto toopen;
error(catgets(catd, 1, 212,
"Can't use visual on a terminal which overstrikes"));
}
if (!CL) {
if (initev)
goto toopen;
error(catgets(catd, 1, 213,
"Visual requires clear screen capability"));
}
if (NS && !SF) {
if (initev)
goto toopen;
error(catgets(catd, 1, 214, "Visual requires scrolling"));
}
resize = SETJMP(venv);
if (resize) {
setsize();
initev = (char *)0;
inopen = 0;
addr1 = addr2 = dot;
}
#ifdef SIGWINCH
signal(SIGWINCH, onwinch);
#endif
ovbeg();
bastate = VISUAL;
c = 0;
if (any(peekchar(), "+-^."))
c = getchar();
pastwh();
vsetsiz(isdigit(peekchar()) ? getnum() : value(WINDOW));
setwind();
newline();
vok(atube);
if (!inglobal)
savevis();
Outchar = vputchar;
vmoving = 0;
f = ostart();
if (initev == 0) {
vcontext(dot, c);
vnline(NOSTR);
}
vmain();
Command = "visual";
ovend(f);
#ifdef SIGWINCH
signal(SIGWINCH, SIG_DFL);
#endif
}
 
/*
* Hack to allow entry to visual with
* empty buffer since routines internally
* demand at least one line.
*/
void
fixzero(void)
{
 
if (dol == zero) {
register bool ochng = chng;
 
vdoappend("");
if (!ochng)
synced();
fixedzero++;
addr1 = addr2 = one;
} else if (addr2 == zero)
addr2 = one;
}
 
/*
* Save lines before visual between unddol and truedol.
* Accomplish this by throwing away current [unddol,truedol]
* and then saving all the lines in the buffer and moving
* unddol back to dol. Don't do this if in a global.
*
* If you do
* g/xxx/vi.
* and then do a
* :e xxxx
* at some point, and then quit from the visual and undo
* you get the old file back. Somewhat weird.
*/
void
savevis(void)
{
 
if (inglobal)
return;
truedol = unddol;
saveall();
unddol = dol;
undkind = UNDNONE;
}
 
/*
* Restore a sensible state after a visual/open, moving the saved
* stuff back to [unddol,dol], and killing the partial line kill indicators.
*/
void
undvis(void)
{
 
if (ruptible)
signal(SIGINT, onintr);
squish();
pkill[0] = pkill[1] = 0;
unddol = truedol;
unddel = zero;
undap1 = one;
undap2 = dol + 1;
undkind = UNDALL;
if (undadot <= zero || undadot > dol)
undadot = zero+1;
}
 
/*
* Set the window parameters based on the base state bastate
* and the available buffer space.
*/
void
setwind(void)
{
 
WCOLS = TCOLUMNS;
switch (bastate) {
 
case ONEOPEN:
if (AM)
WCOLS--;
/* fall into ... */
 
case HARDOPEN:
basWTOP = WTOP = WBOT = WECHO = 0;
ZERO = 0;
holdcm++;
break;
 
case CRTOPEN:
basWTOP = TLINES - 2;
/* fall into */
 
case VISUAL:
ZERO = TLINES - TUBESIZE / WCOLS;
if (ZERO < 0)
ZERO = 0;
if (ZERO > basWTOP)
error(catgets(catd, 1, 215,
"Screen too large for internal buffer"));
WTOP = basWTOP; WBOT = TLINES - 2; WECHO = TLINES - 1;
break;
}
state = bastate;
basWLINES = WLINES = WBOT - WTOP + 1;
}
 
/*
* Can we hack an open/visual on this terminal?
* If so, then divide the screen buffer up into lines,
* and initialize a bunch of state variables before we start.
*/
void
vok(register cell *atube)
{
register int i;
 
if (WCOLS == 1000)
serror(catgets(catd, 1, 216,
"Don't know enough about your terminal to use %s"), Command);
if (WCOLS > TUBECOLS)
error(catgets(catd, 1, 217, "Terminal too wide"));
if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE)
error(catgets(catd, 1, 218, "Screen too large"));
 
vtube0 = atube;
vclrcell(atube, WCOLS * (WECHO - ZERO + 1));
for (i = 0; i < ZERO; i++)
vtube[i] = (cell *) 0;
for (; i <= WECHO; i++)
vtube[i] = atube, atube += WCOLS;
for (; i < TUBELINES; i++)
vtube[i] = (cell *) 0;
vutmp = (char *)atube;
vundkind = VNONE;
vUNDdot = 0;
OCOLUMNS = TCOLUMNS;
inopen = 1;
signal(SIGINT, vintr);
vmoving = 0;
splitw = 0;
doomed = 0;
holdupd = 0;
Peekkey = 0;
vcnt = vcline = 0;
if (vSCROLL == 0)
vSCROLL = value(SCROLL);
/*old vSCROLL = (value(WINDOW)+1)/2;*//* round up so dft=6,11 */
}
 
void
vintr(int signum)
{
extern JMP_BUF readbuf;
extern int doingread;
 
signal(SIGINT, vintr);
if (vcatch)
onintr(SIGINT);
ungetkey(ATTN);
draino();
if (doingread) {
doingread = 0;
LONGJMP(readbuf, 1);
}
}
 
/*
* Set the size of the screen to size lines, to take effect the
* next time the screen is redrawn.
*/
void
vsetsiz(int size)
{
register int b;
 
if (bastate != VISUAL)
return;
b = TLINES - 1 - size;
if (b >= TLINES - 1)
b = TLINES - 2;
if (b < 0)
b = 0;
basWTOP = b;
basWLINES = WBOT - b + 1;
}
 
#ifdef SIGWINCH
void
onwinch(int signum)
{
vsave();
setty(normf);
LONGJMP(venv, 1);
}
#endif
/ports/trunk/editors/exvi/ex_version.c
0,0 → 1,90
/*
* 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.
*
* Sccsid @(#)ex_version.c 1.132 (gritter) 3/25/05
*/
 
#include "ex.h"
 
static char *versionstring = "@(#)Version 4.0 (gritter) 3/25/05";
 
void
printver(void)
{
printf("%s%s%s", versionstring + 4,
#ifdef BIT8
"", ""
#else
",", "@(#) 7bit" + 4
#endif
);
}
/ports/trunk/editors/exvi/Changes
0,0 → 1,241
Release 3/25/05
* vi no longer dies with a segmentation fault if a line does not fit on the
screen after an insertion.
* The 'p' command now works correctly if the buffer contains a partial line
with multibyte characters.
* Traditional regular expressions sometimes failed to operate correctly
since the last release.
 
Release 2/25/05
* Traditional regular expressions can now be used with multibyte characters.
* When the 'ignorecase' option is toggled, saved regular expressions are now
updated accordingly. (P)
* If a line began with a tabulator and another tabulator was inserted with
the cursor located on the first tabulator, the display was not updated
appropriately since the last release (Bugreport by Matthew Fischer). (P)
* Fixed a segmentation fault that occured in multibyte locales when operation
was continued after vi had been stopped by ^Z, with the cursor positioned
in a line longer than the terminal width as the last line of the current
screen.
* Made multicolumn characters work in lines longer than the screen width in
visual mode (Bugreport by Matthew Fischer).
* Made it work for Big5 locales (Patches by Matthew Fischer).
* Fixed a problem with the 'r' command in EUC-JP and Big5 locales (Bugreport
by Matthew Fischer).
* The insertion of multicolumn characters and tab characters in multibyte
locales now works with terminals that have the 'ic' but no 'im' termcap
capability (Bugreport by Matthew Fischer).
* The argument to the -w option is correctly recognized now.
* If the SHELL environment variable is set to the empty string, it is now
ignored.
* A non-null exit status is now returned if a file could not be opened, if
an invalid address is given for a command, or if a tag is not found.
* If the match for a substitution is of length zero, a line overflow is
now avoided when compiled with the 'UNIX(R) Regular Expression Library'.
* When moving left while the cursor is positioned over a multicolumn
character at the end of the line, the bell is rung now (Bugreport by
Matthew Fischer).
* When moving up or down to a row with different column arrangement while
the cursor is positioned over a multicolumn character, the leftmost
character above the original position is chosen in the new row.
* If both the -t and the -c option are given, the -t option is now
processed first, i.e. the command is executed at the position where
the tag was found.
* The -w option now also sets the scroll size for the 'z' command.
* When the name of a nonexisting file is given with the 'edit' ex command,
the command now succeeds and prints a "[New file]" message.
* If standard output is not a terminal, no '\r' is written at the end of
printed lines anymore.
* The 'source' ex command now works if command input comes from a pipe or
regular file.
* Ex does not exit on errors immediately anymore if standard input is not
a terminal but a pipe or regular file.
* The 'substitute' ex command can now be abbreviated as 'sub', 'subst' etc.
* A new version of mapmalloc.c that is derived from Unix 7th Edition code
has been introduced.
* If the 'next!' ex command is given and the autowrite option is set, the
current file is not written anymore.
 
Release 1/19/05
* The last release erroneously made 'X' work like 'x' in visual mode. It now
deletes the character before the cursor again as documented (Bugreport by
Matthew Fischer). (P)
* When a multicolumn character was replaced by another multicolumn character
in insert mode, the display was not updated appropriately with terminals
other than xterm.
* Various rendering errors happened with multicolumn characters if they
started at an even column (counting from 1 upwards).
* When a multicolumn character was inserted and then replaced, the visual
screen representation was sometimes not updated accordingly.
* Undoing the replacement of a multicolumn character by a singlecolumn
character twice made the singlecolumn character invisible.
* The 'cw' visual command with a multibyte character as last character of
the affected word located at the end of the line left garbage bytes past
the end of the new text.
* Visual 'U' followed by 'u' lead to garbage on the screen when multibyte
characters were present on the changed line.
* The position of '$' when changing text was fixed for cases where the first
changed character had multiple columns but the last one had not.
* The handling of multicolumn characters was fixed for terminals without the
IM (insert mode) capability. It is unlikely that such terminals actually
exist, but vi will use the corresponding code for open mode if a termcap
entry is not available.
* When an illegal multibyte sequence is entered in vi insert mode, no garbage
bytes are generated anymore when the insert mode is left.
* The '\u', '\l', '\U', and '\L' substitution sequences work with multibyte
characters now.
* Handle character case conversions with the '~' vi command correctly if the
length of the converted multibyte sequence is smaller than the original one.
* Multibyte sequences that correspond to an unprintable character are now
printed as multiple octal escape sequences.
* Pressing the ^U (kill) character in insert mode with a multibyte character
at the beginning of an insertion at the start of a line sometimes positioned
the cursor at weird locations since the last revision.
* Fixed an old vi bug: If a vi command that yanked or deleted part of a line
was followed by an ex command that also yanked or deleted some text, a
following 'p' vi command pasted the text affected by the former vi command.
It now pastes the text of the last yank or delete even if that was an ex
command.
* Some build fixes for diet libc have been made.
 
Release 12/2/04
* Support for multibyte character locales was added.
* The code has been converted to ANSI C, and support for pre-POSIX systems has
been dropped.
* When the end of the current line consists of blank characters and the 'w'
visual command is given at this point, vi now advances to the start of the
next line instead of ringing the bell. This is compatible with SVR4 vi and
seems to be what POSIX specifies.
* If the replacement part of a substitute command consists of a single '%',
as in ':s/foo/%/', the replacement part of the previous substitution is
used. This is compatible with SVR4 vi and is specified by POSIX.
* Fixed a number of possible heap overflows, e.g. because of too long tag
strings.
 
Release 6/5/04
* Some changes were made to the Makefile to support RPM builds. In particular,
the meaning of the DESTDIR and PREFIX variables was changed.
* An insufficient size of a variable caused the window size set to 8 on
FreeBSD if the terminal baud rate was 38400.
 
Release 1/3/04
* Changes to the included libterm only: Made multiple tc= capabilities in
a termcap entry work; recognize tc= also if it is not the last capability
in an entry (Bugreport by Andrew Minter).
 
Release 9/3/03
* The code did not check st_blksize from stat(2) at other points besides
the one fixed in the last release.
* The keyboard input character with code 255 ("y in ISO-8859-1) was
misinterpreted as end-of-file indicator.
 
Release 8/27/03
* Compile fixes for AIX and HP-UX (Mike Jetzer).
* Delete temporary file when preserving was successful after receiving
SIGHUP or SIGTERM (Fix taken from 4.3BSD Reno).
* Set MAILRC to /dev/null in expreserve to avoid reading the user's
mail initialization file.
* Optionally use Caldera's 'UNIX(R) Regular Expression Library' to
get POSIX.2 compatible REs.
* Don't refuse to quit with 'No write since last change' if a line of a
newly read input file is too long but no changes were made by the user.
* The POSIX_2 preprocessor define has been removed. The behavior previously
enabled by this variable is now the default (except as noted below).
* Backslash inside RE bracket expresssions (as in [\]]) is now recognized
as an escape character by default. This is not POSIX.2 compliant, but is
compatible with historic vi behavior, is demanded by the some traditional
standards such as the System V Interface definition, and is compatible
with vim. To get POSIX.2 compliant behavior here, define NO_BE_BACKSLASH.
* The input buffer did overflow with large values of st_blksize from stat(2).
 
Release 4/3/02
* Option "showmode" has no effect on hardcopy or glass terminals (P).
* Fixed undo for :r! command.
* Interrupt character is not misinterpreted as DEL on insertion (P).
* Fixed interaction of <count>~ vi command with abbreviations and macros (P).
* Avoid horizontal scrolling of showmode string on wraparound to last line (P).
* No showmode string is printed when executing a macro.
* Recovery listing fixed not to mix characters from long filenames in
/var/preserve with /var/tmp listing (P).
* Catch SIGXFSZ (file size limit exceeded).
 
Release 3/3/02
* Separated terse/noterse messages for RE errors (P).
* The expreserve and exrecover commands work again (P).
* Passing beyond EOL in <count>~ vi command is not an error (P).
* Fixed segmentation violation on mdjc'd and related bugs (Sven Mascheck).
* Marks remain on lines changed in an undo operation.
* Close mapmalloc file descriptor for /dev/zero on exec() (P).
* Added -L and -V command line options as in SVr4 ex.
* POSIX.2: Processing EXINIT does not depend on stdin being a terminal.
* POSIX.2: No newline is appended to an empty file in visual mode.
* Fixed segmentation violation on :f^V^M^M and similar commands.
* Mapmalloc extended to allocate and release multiple memory pools.
* Exrecover lists /var/tmp in addition to /var/preserve.
* Have multiple attempts to create named buffer temporary file.
* Size limit for temporary file names removed.
 
Release 2/17/02
* POSIX.2: Backslash has no special meaning inside RE bracket expressions.
* RE cleanup; make it compile without POSIX_2 defined (P).
* Fixed $(CC) to "$(CC)" for libterm compilation (Felix von Leitner) (P).
* Support for LC_MESSAGES using catgets() added.
* Renamed POSIX define to POSIX_1.
* Renamed UNIX98 define to POSIX_2.
* POSIX.2: Fixed a conflict between -t tag and wrapscan option.
* POSIX.2: Take the initial value for the vi scroll command from scroll var.
* <count>~ vi command fixed to work with repeat and control chars in text (P).
* Fixed recursion on :ab abbreviations (Bugreport by Matthias Kopfermann).
* Fixed undo for :<addr>r command in visual mode.
* Made modelines compatible to SVr4 ex: The option name is "modelines" or
"ml" now; a space or tab preceeding "ex:" or "vi:" is not required.
* Use O_EXCL and O_NOFOLLOW when creating temporary files, if possible.
 
Release 1/26/02
* Use mmap() for memory allocation if possible.
* POSIX.2: Added RE interval expressions \{m,n\} (taken from V7 expr).
* POSIX.2: Added backreferences \1 ... \9.
* Print one-character mode strings if both "showmode" and "terse" are set.
* Added the "flash" variable.
* POSIX.2: "~" visual command accepts a count.
* License notices added.
 
Release 5/21/01
* If compiled using BIT8, all characters except ASCII NUL can now be handled.
* Support larger files if LARGEF is defined.
 
Release 09/23/00
* POSIX locale support for 8bit character sets is enabled by -DBIT8.
* Regex code is 8bit clean.
* Smaller fixes for SVR4 systems.
* POSIX termios support including job control.
* POSIX sigaction support.
* Check for ELF executables and compressed files.
* Extended the pattern for temporary files from 5 to 10 digits.
* ANSI C stdarg function calling added, Linux/ia64 needs them.
* Reintegrated the UCVISUAL routines from 4.4BSD ex.
* Only use the "ic" termcap sequence if "im" is empty.
* POSIX.2: Command line options added and revised.
* POSIX.2: Added a "showmode" option for novices.
* POSIX.2: Ex respects the environment variables COLUMNS and LINES.
* POSIX.2: Added an "exrc" option like on POSIX.2 ex; arbitrary .exrc
files are ignored unless it is set in EXINIT or ~/.exrc.
* POSIX.2: If .exrc files are world or group writeable, they are ignored
unless "sourceany" is set.
* Ex now provides malloc routines. They are necessary since C library
calls like setlocale could otherwise break the sbrk calls in ex. As
an additional benefit, linking against ncurses is now possible.
 
Release 31/05/00
* String extraction using mkstr and xstr is not longer be done.
* An ANSI C preprocessor may be used.
* Changes of symbol names due to collisions on newer systems.
* Fixed a null pointer reference in ex_tty.c.
* Included the 2.11BSD termcap in a subdirectory. Ex could use any
termcap library, however, that does not use malloc().
* Support of eight bit characters excluding the range 0200 to 0237 is
enabled with -DISO8859_1. It does not include the regular expression code,
but otherwise works well in practice with the ISO-8859-1 character set.
 
Fixes for problems that were introduced in this port are marked (P), unless
they only affect newly introduced parts (such as multibyte support).
/ports/trunk/editors/exvi/LICENSE
0,0 → 1,69
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.
/ports/trunk/editors/exvi/Makefile
0,0 → 1,392
#
# 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.
#
# from Makefile 7.13.1.3 (2.11BSD GTE) 1996/10/23
#
# @(#)Makefile 1.50 (gritter) 2/20/05
#
 
#
# Destinations for installation. $(PRESERVEDIR) is used for recovery files.
# It will get mode 1777.
#
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
LIBEXECDIR = $(PREFIX)/libexec
MANDIR = $(PREFIX)/share/man
PRESERVEDIR = /var/preserve
 
#
# DESTDIR is prepended to the installation paths. It is mostly useful
# for package building and should be left empty otherwise.
#
DESTDIR =
 
#
# A BSD-like install program. GNU install will fit well here, too.
#
INSTALL = /usr/ucb/install
 
#
# Compiler and linker flags.
#
# On HP-UX, add -D_INCLUDE__STDC_A1_SOURCE to CPPFLAGS.
#
#CFLAGS =
#CPPFLAGS =
#LDFLAGS =
#LDADD =
 
#
# All of the following settings are quite recommended, so you should only
# change them if it becomes really necessary.
#
# Remove -DMB to build without multibyte character support. This will be
# necessary if the compiler complains about a missing wchar.h, wctype.h,
# mbtowc(), mbrtowc(), btowc(), wcwidth() etc. You will likely also have
# to use the old regular expression code in these cases (see below).
# Remove -DBIT8 to get a 7bit-only ex. This setting is mostly provided for
# testing the internationalization code against the older version and
# should not normally be removed.
# Add -DNO_BE_BACKSLASH to make backslash a regular character inside RE
# bracket expressions. This is required for POSIX conformance but
# conflicts with historical practice for ex.
#
# Some historic comments:
#
# Ex is very large - this version will not fit on PDP-11's without overlay
# software. Things that can be turned off to save
# space include LISPCODE (-l flag, showmatch and lisp options), CHDIR (the
# previously undocumented chdir command.)
#
# If your system expands tabs to 4 spaces you should -DTABS=4 below
#
FEATURES = -DLISPCODE -DCHDIR -DFASTTAG -DUCVISUAL -DMB -DBIT8
 
#
# This disables the LC_CTYPE locale settings and assumes all characters
# upwards from octal 0240 are printable ones, like in ISO 8859-1. It
# should only be used if the system's locales are broken. It cannot be
# used in combination with -DMB.
#
#CHARSET = -DISO8859_1
 
#
# If you want LC_MESSAGES support using catgets(), define this. To make
# any practical use of it, you also have to create a message catalogue,
# put it in a proper location and change UNKNOWN to its name. See your
# system's documentation on "gencat" or on language support in general
# for further information. This setting is not interesting at the current
# time unless you want to contribute internationalized message catalogues.
#
#LANGMSG = -DLANGMSG -DCATNAME='"UNKNOWN"'
 
#
# For POSIX regular expressions, e.g. the star applied to subexpressions
# as in \(ab\)* and localized regular expressions like [:class:], [.c.],
# and [=c=], you need Caldera's 'UNIX(R) Regular Expression Library' or
# the included derivative of it.
#
# Comment out the three following lines if you do not have it or if it
# does not compile; it needs some advanced multibyte character support
# (wchar.h, wctype.h, btowc() etc.) which is not provided by older
# compilation environments.
#
REINC = -I./libuxre -DUXRE
RELIB = -L./libuxre -luxre
RETGT = uxre
 
#
# VMUNIX should be correct for any modern Unix.
#
# Historic comments:
#
# VMUNIX makes ex considerably larger, raising
# many limits and improving speed and simplicity of maintenance. It is
# suitable only for a VAX or other large machine, and then probably only in
# a paged system.
#
# Don't define VFORK unless your system has the VFORK system call,
# which is like fork but the two processes have only one data space until the
# child execs. This speeds up ex by saving the memory copy.
#
# Note by Gunnar Ritter: vfork() is unreliable and one of the worst
# hacks in Unix history. Do not define VFORK unless you have a
# special good reason for that.
#
OSTYPE = -DVMUNIX
 
#
# On VMUNIX systems, ex can normally edit files up to 32 MB of size. LARGEF
# raises this limit to around 1 GB, but ex will consume much more of core
# and temp file space then.
#
#LARGEF = -DLARGEF
 
#
# The next setting is a crucial one since it determines the way ex
# gets its knowledge about the terminal's capabilities. If you get
# weird results, try using another library here. Uncomment exactly
# one entry.
#
# On System V, the terminfo library may be more accurate than the termcap
# file. To use it, link against the curses library.
#
#TERMLIB = curses
#
# You may also get terminfo access by using the ncurses library.
#
#TERMLIB = ncurses
#
# The preferred choice for ex on Linux distributions, other systems that
# provide a good termcap file, or when setting the TERMCAP environment
# variable is deemed sufficient, is the included 2.11BSD termcap library.
#
TERMLIB = termlib
 
#
# Since ex uses sbrk() internally, a conflict with the libc's version of
# malloc() must be avoided. There are two ways to work around this problem.
# The first is to allocate a static pool for all malloc purposes. This will
# work on any kind of system.
#
#MALLOC=malloc.o
#
# If mmap() can be used to allocate anonymous memory, this is the preferred
# choice as it allows to grow memory dynamically as it is needed. This will
# usually work unless you are compiling for a vector machine or another
# unusual enviroment.
MALLOC=mapmalloc.o
 
###############################################################################
# #
# That's it. You do not normally need to change anything below here. #
# #
###############################################################################
 
#WARN = -Wall -Wno-parentheses -Werror
 
STRIP = -s
RECOVER = -DEXRECOVER=\"$(LIBEXECDIR)/exrecover\" \
-DEXPRESERVE=\"$(LIBEXECDIR)/expreserve\"
CCFLAGS = $(CFLAGS) $(WARN) $(CPPFLAGS) $(FEATURES) $(CHARSET) $(OSTYPE) \
$(LARGEF) $(RECOVER) $(LANGMSG) $(REINC) $(RPMCFLAGS)
TLIB = libterm/libtermlib.a
INCLUDE = /usr/include
OBJS = ex.o ex_addr.o ex_cmds.o ex_cmds2.o ex_cmdsub.o \
ex_data.o ex_extern.o ex_get.o ex_io.o ex_put.o ex_re.o \
ex_set.o ex_subr.o ex_tagio.o ex_temp.o ex_tty.o ex_unix.o \
ex_v.o ex_vadj.o ex_vget.o ex_vmain.o ex_voper.o \
ex_vops.o ex_vops2.o ex_vops3.o ex_vput.o ex_vwind.o \
printf.o ex_version.o $(MALLOC)
HDRS = ex.h ex_argv.h ex_re.h ex_temp.h ex_tty.h ex_tune.h ex_vars.h \
ex_vis.h libterm/libterm.h
SRC1 = ex.c ex_addr.c ex_cmds.c ex_cmds2.c ex_cmdsub.c
SRC2 = ex_data.c ex_get.c ex_io.c ex_put.c ex_re.c
SRC3 = ex_set.c ex_subr.c ex_tagio.c ex_temp.c ex_tty.c ex_unix.c
SRC4 = ex_v.c ex_vadj.c ex_vget.c ex_vmain.c ex_voper.c
SRC5 = ex_vops.c ex_vops2.c ex_vops3.c ex_vput.c ex_vwind.c
SRC6 = printf.c expreserve.c exrecover.c ex_version.c
SRC7 = mapmalloc.c malloc.c
 
.SUFFIXES: .o .c
.c.o: ; $(CC) $(CCFLAGS) -c $<
 
all: $(RETGT) exrecover expreserve ex
 
ex: $(TLIB) $(OBJS)
$(CC) -o ex $(LDFLAGS) $(OBJS) $(LDADD) -Llibterm -l$(TERMLIB) $(RELIB)
size ex
 
$(TLIB): libterm/termcap.c libterm/tgoto.c libterm/tputs.c libterm/libterm.h
@cd libterm && $(MAKE) CC="$(CC)" \
COPT="$(CFLAGS) $(WARN) $(CPPFLAGS) $(OSTYPE)"
 
exrecover: exrecover.o $(MALLOC)
$(CC) -o exrecover $(LDFLAGS) exrecover.o $(MALLOC) $(LDADD)
 
expreserve: expreserve.o
$(CC) -o expreserve $(LDFLAGS) expreserve.o $(LDADD)
 
ex_vars.h: ex_data.c
sh makeoptions $(CCFLAGS)
 
uxre:
@cd libuxre && $(MAKE) CC="$(CC)" \
COPT="$(CFLAGS) $(WARN) $(CPPFLAGS) $(OSTYPE)"
 
clean:
@cd libterm && $(MAKE) clean
@test ! -d libuxre || (cd libuxre && $(MAKE) clean)
# If we dont have ex we cant make it so don't rm ex_vars.h
-rm -f ex exrecover expreserve *.o x*.[cs] core errs trace
 
mrproper: clean
-rm -f log
 
# install in standard place
 
install-man:
test -d $(DESTDIR)$(PREFIX) || mkdir -p $(DESTDIR)$(PREFIX)
test -d $(DESTDIR)$(MANDIR) || mkdir -p $(DESTDIR)$(MANDIR)
test -d $(DESTDIR)$(MANDIR)/man1 || mkdir -p $(DESTDIR)$(MANDIR)/man1
rm -f $(DESTDIR)$(MANDIR)/man1/ex.1 $(DESTDIR)$(MANDIR)/man1/edit.1 \
$(DESTDIR)$(MANDIR)/man1/vedit.1 \
$(DESTDIR)$(MANDIR)/man1/vi.1 \
$(DESTDIR)$(MANDIR)/man1/view.1
$(INSTALL) -c -m 644 ex.1 $(DESTDIR)$(MANDIR)/man1/ex.1
$(INSTALL) -c -m 644 vi.1 $(DESTDIR)$(MANDIR)/man1/vi.1
ln -s ex.1 $(DESTDIR)$(MANDIR)/man1/edit.1
ln -s vi.1 $(DESTDIR)$(MANDIR)/man1/vedit.1
ln -s vi.1 $(DESTDIR)$(MANDIR)/man1/view.1
 
install: all install-man
rm -f $(DESTDIR)$(BINDIR)/ex $(DESTDIR)$(BINDIR)/edit \
$(DESTDIR)$(BINDIR)/vedit $(DESTDIR)$(BINDIR)/vi \
$(DESTDIR)$(BINDIR)/view
test -d $(DESTDIR)$(BINDIR) || mkdir -p $(DESTDIR)$(BINDIR)
# special provisions for sticky install
if test -f $(DESTDIR)$(BINDIR)/ex; \
then test -f $(DESTDIR)$(BINDIR)/ex.old.$$$$ && exit 1; \
chmod 755 $(DESTDIR)$(BINDIR)/ex; \
echo q | $(DESTDIR)$(BINDIR)/ex; \
mv $(DESTDIR)$(BINDIR)/ex $(DESTDIR)$(BINDIR)/ex.old.$$$$; \
rm -f $(DESTDIR)$(BINDIR)/ex.old.$$$$; \
fi
$(INSTALL) -c $(STRIP) -m 1755 ex $(DESTDIR)$(BINDIR)/ex
test -d $(DESTDIR)$(LIBEXECDIR) || mkdir -p $(DESTDIR)$(LIBEXECDIR)
$(INSTALL) -c $(STRIP) exrecover $(DESTDIR)$(LIBEXECDIR)/exrecover
$(INSTALL) -c $(STRIP) expreserve $(DESTDIR)$(LIBEXECDIR)/expreserve
ln -s ex $(DESTDIR)$(BINDIR)/edit
ln -s ex $(DESTDIR)$(BINDIR)/vedit
ln -s ex $(DESTDIR)$(BINDIR)/vi
ln -s ex $(DESTDIR)$(BINDIR)/view
test -d $(DESTDIR)$(PRESERVEDIR) || mkdir -p $(DESTDIR)$(PRESERVEDIR)
chmod 1777 $(DESTDIR)$(PRESERVEDIR)
 
ex.o: config.h ex_argv.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h
ex.o: ex_vars.h libterm/libterm.h
ex_addr.o: config.h ex.h ex_proto.h ex_re.h ex_tune.h ex_vars.h
ex_cmds.o: config.h ex_argv.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h
ex_cmds.o: ex_vars.h ex_vis.h libterm/libterm.h
ex_cmds2.o: config.h ex_argv.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h
ex_cmds2.o: ex_vars.h ex_vis.h libterm/libterm.h
ex_cmdsub.o: config.h ex_argv.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h
ex_cmdsub.o: ex_vars.h ex_vis.h libterm/libterm.h
ex_data.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h
ex_data.o: libterm/libterm.h
ex_extern.o: config.h ex_argv.h ex.h ex_proto.h ex_re.h ex_temp.h ex_tty.h
ex_extern.o: ex_tune.h ex_vars.h ex_vis.h libterm/libterm.h
ex_get.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h
ex_get.o: libterm/libterm.h
ex_io.o: config.h ex_argv.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h
ex_io.o: ex_vars.h ex_vis.h libterm/libterm.h
ex_put.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_put.o: libterm/libterm.h
ex_re.o: config.h ex.h ex_proto.h ex_re.h ex_tune.h ex_vars.h
ex_set.o: config.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h ex_vars.h
ex_set.o: libterm/libterm.h
ex_subr.o: config.h ex.h ex_proto.h ex_re.h ex_tty.h ex_tune.h ex_vars.h
ex_subr.o: ex_vis.h libterm/libterm.h
ex_tagio.o: config.h ex.h ex_proto.h ex_tune.h ex_vars.h
ex_temp.o: config.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h ex_vars.h
ex_temp.o: ex_vis.h libterm/libterm.h
ex_tty.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h
ex_tty.o: libterm/libterm.h
ex_unix.o: config.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h ex_vars.h
ex_unix.o: ex_vis.h libterm/libterm.h
ex_v.o: config.h ex.h ex_proto.h ex_re.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_v.o: libterm/libterm.h
ex_vadj.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_vadj.o: libterm/libterm.h
ex_vget.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_vget.o: libterm/libterm.h
ex_vmain.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_vmain.o: libterm/libterm.h
ex_voper.o: config.h ex.h ex_proto.h ex_re.h ex_tty.h ex_tune.h ex_vars.h
ex_voper.o: ex_vis.h libterm/libterm.h
ex_vops.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_vops.o: libterm/libterm.h
ex_vops2.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_vops2.o: libterm/libterm.h
ex_vops3.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_vops3.o: libterm/libterm.h
ex_vput.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_vput.o: libterm/libterm.h
ex_vwind.o: config.h ex.h ex_proto.h ex_tty.h ex_tune.h ex_vars.h ex_vis.h
ex_vwind.o: libterm/libterm.h
expreserve.o: config.h
exrecover.o: config.h ex.h ex_proto.h ex_temp.h ex_tty.h ex_tune.h ex_vars.h
exrecover.o: libterm/libterm.h
malloc.o: config.h
mapmalloc.o: config.h
printf.o: config.h
/ports/trunk/editors/exvi/README
0,0 → 1,145
Welcome to the ex/vi port!
==========================
 
This implementation is derived from ex/vi 3.7 of 6/7/85 and the BSD
termcap library, originally from the 2.11BSD distribution. All of them
were changed to compile and run on newer POSIX compatible Unix systems.
Support for international character sets was added, including support
for multibyte locales (based on UTF-8 or East Asian encodings), and some
changes were made to get closer to the POSIX.2 guidelines for ex and
vi. Some issues that were clearly bugs and not features have also been
resolved; see the Changes file for details.
 
New releases are announced on Freshmeat. If you want to get
notified by email on each release, use their subscription service at
<http://freshmeat.net/projects/vi/>.
 
The project homepage is currently at <http://ex-vi.sourceforge.net>.
 
 
How to build
============
 
First look at the Makefile and change the settings there to match your
build environment. Explanations are provided directly in this file.
 
You can tune the sizes of some internal buffers by editing config.h. In
particular, you will have to raise the size of the 'TUBE' constants if
you wish to use really large-sized terminals.
 
Then type 'make' and 'make install'.
 
It is possible to build a RPM file directly from the source distribution
by executing
 
rpmbuild -tb ex-<version>.tar.bz2
 
Note that the RPM spec installs the binary in /usr/5bin by default to
avoid conflicts with vendor files in /usr/bin. The default locations
match those of the Heirloom Toolchest <http://heirloom.sourceforge.net>.
 
The following systems have been reported to compile this code:
 
Linux Kernel 2.0 and above; libc4, libc5, glibc 2.2 and above,
diet libc, uClibc
Sun Solaris 2.5.1 and above
Caldera Open UNIX 8.0.0
SCO UnixWare 7.1.1, 7.0.1, 2.1.2
HP HP-UX B.11.23, B.11.11, B.11.00, B.10.20
HP Tru64 UNIX 4.0G, 5.1B
IBM AIX 5.1, 4.3
NEC SUPER-UX 10.2
NEC UX/4800 Release11.5 Rev.A
Control Data EP/IX 2.2.1AA
FreeBSD 3.1, 4.5, 5.x
NetBSD 1.6, 2.0
 
Reports about other Unix systems are welcome, whether successful or not
(in the latter case add a detailed description). This port of vi is only
aimed at Unix, though, so I am not interested about results from running
this software on Windows etc.
 
Prerequisites for ports to other systems are:
 
- The system must provide an ANSI C-89 compiler and POSIX.1-1990 functions.
 
- The system must provide an sbrk() call to increase the memory heap size.
If only a fake sbrk() call is provided that works by pre-allocating
several MB, vi will probably work too.
 
- The system library must allow replacement of malloc() and printf() by the
versions provided by vi. For malloc(), it also must make its own internal
memory requests using the vi malloc(). Otherwise, vi will likely die with
a segmentation fault because the storage allocated by sbrk() interferes
with usual Unix library implementations of malloc().
 
The last two requirements could probably be eliminated with some effort, but
it would not result in any real improvements for usual the Unix platforms vi
is targeted at, so it has not be done yet.
 
 
Terminal capabilities
=====================
 
vi normally uses the termcap library to gather information about the
capabilities of the terminal it is using. A BSD-derived termcap library
is included with the vi distribution, and is usually the preferred choice.
On some platforms, though, either no /etc/termcap file exists, or the file
lacks up-to-date entries. In these cases, two workarounds are possible.
First, vi can be linked against libcurses, libncurses, or libtermcap, if
these provide access to a proper terminal information database. Second, it
is possible to use the included termcap library with a TERMCAP environment
variable that contains a complete termcap entry. Most terminals in current
use provide a superset of DEC VT102 capabilities, so the following will
normally work:
 
TERMCAP="vt102|$TERM|dec vt102:"'\
:do=^J:co#80:li#24:cl=50\E[;H\E[2J:\
:le=^H:bs:cm=5\E[%i%d;%dH:nd=2\E[C:up=2\E[A:\
:ce=3\E[K:cd=50\E[J:so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:\
:md=2\E[1m:mr=2\E[7m:mb=2\E[5m:me=2\E[m:is=\E[1;24r\E[24;1H:\
:rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:ks=\E[?1h\E=:ke=\E[?1l\E>:\
:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\
:ho=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=5\EM:vt#3:\
:sc=\E7:rc=\E8:cs=\E[%i%d;%dr:vs=\E[?7l:ve=\E[?7h:\
:mi:al=\E[L:dc=\E[P:dl=\E[M:ei=\E[4l:im=\E[4h:'
export TERMCAP
 
 
Multibyte locale support
========================
 
Support for multibyte locales has been added to vi. It requires a number of
functions that, while specified in XPG6, are not present on all systems that
provide basic multibyte support. In particular, vi needs wcwidth() to
determine the visual width of a character, and mbrtowc() to detect when a
byte sequence that is entered at the terminal has been completed.
 
The multibyte code is known to work on the following systems:
 
Linux glibc 2.2.2 and later
Sun Solaris 9 and later
HP HP-UX B.11.11 and later
FreeBSD 5.3
NetBSD 2.0
 
It has been tested on xterm patch #192, rxvt-unicode 4.2, mlterm 2.9.1, and
xiterm 0.5.
 
Successful operation is known for the following encodings: UTF-8, EUC-JP,
EUC-KR, Big5, Big5-HKSCS, GB 2312, GBK. vi does not support locking-shift
encodings like those that use ISO 2022 escape sequences. It also requires
that the first byte of any multibyte character has the highest bit set.
This excludes 7-bit encodings like UTF-7, and encodings whose sequences
start with ASCII characters like TCVN 5712.
 
To use UTF-8 locales in ex mode, the terminal should be put in 'stty iutf8'
mode on Linux if it does not perform this automatically. Otherwise, typing
the erase key once after entering a multibyte character will result in an
incomplete byte sequence.
 
 
Gunnar Ritter 2/20/05
Freiburg i. Br.
Germany
<Gunnar.Ritter@pluto.uni-freiburg.de>
/ports/trunk/editors/exvi/TODO
0,0 → 1,12
TODO list for ex
 
- Some support for UTF-8 combining characters should probably be added.
 
- Since the POSIX standard developers did not include a method to
determine whether something is a valid collation symbol or an
equivalence class, and since there is no access to the basic
collation sequence, LC_COLLATE locales are completely ignored.
 
- SVr4 ex probably has some silent features that this one should have too.
 
Gunnar Ritter 2/19/05
/ports/trunk/editors/exvi/catd/en_US
0,0 → 1,309
$ Message catalogue for ex/vi
$ Sccsid @(#)en_US 1.4 (gritter) 3/18/03
$quote "
$set 1
1 "Usage: %s [- | -s] [-l] [-L] [-R] [-r [file]] [-t tag]\n\
[-v] [-V] [-w size] [+cmd | -c cmd] file...\n"
2 "%s: option requires an argument -- %c\n"
3 "%s: illegal option -- %c\n"
4 "Trace create error\n"
5 "Unknown option %s\n"
6 "Addr1 > addr2|First address exceeds second"
7 "Bad count|Nonzero count required"
8 "No address allowed@on this command"
9 "Badly formed address"
10 "No match to BOTTOM|Address search hit BOTTOM without matching pattern"
11 "No match to TOP|Address search hit TOP without matching pattern"
12 "Fail|Pattern not found"
13 "Marks are ' and a-z"
14 "Undefined mark@referenced"
15 "Negative address@- first buffer line is 1"
16 "Not that many lines@in buffer"
17 "Offset out-of-bounds|Offset after command too large"
18 "Home directory unknown"
19 "Mark what?|%s requires following letter"
20 "Bad mark|Mark must specify a letter"
21 "Preserve failed!"
22 "File preserved."
23 "No write@since last change (:rewind! overrides)"
24 "Old tty driver|Not using new tty driver/shell"
25 "Bad register"
26 "At EOF|At end-of-file"
27 "What?|Unknown command character '%c'"
28 "Extra chars|Extra characters at end of command"
29 " [Warning - %s is incomplete]"
30 "%d files@to edit"
31 "No more files@to edit"
$quote
32 Extra chars|Extra characters at end of "%s" command
$quote "
33 "%d more file"
34 "%s@to edit"
35 "No write@since last change (:%s! overrides)"
36 "What?|%s: No such command from open/visual"
37 "What?|%s: Not an editor command"
38 "[Hit return to continue] "
39 "Out of memory@- too many lines in file"
40 "Line overflow|Result line of join would be too long"
41 "That move would do nothing!"
42 "Move to a moved line"
43 "%s where?|%s requires a trailing address"
44 "Cannot put inside global/macro"
45 "Line too long|Result line after shift would be too long"
46 "Bad tag|Give one tag per line"
47 "No previous tag"
48 "%s: Bad tags file entry"
49 "No write@since last change (:tag! overrides)"
50 "No tags file"
51 "%s: No such tag@in tags file"
52 "Can't yank inside global/macro"
53 "\nAt EOF"
54 "At EOF"
55 "Hit BOTTOM"
56 "Hit TOP"
57 "Nothing to undo"
58 "Nothing changed|Last undoable command didn't change anything"
59 "Can't undo in global@commands"
60 "Missing lhs"
61 "Missing rhs"
62 "Missing rhs"
63 "No tail recursion"
64 "Too dangerous to map that"
65 "No tail recursion"
66 "Missing lhs"
67 "Not mapped|That macro wasn't mapped"
68 "Too many macros"
69 "Too much macro text"
70 "^H discarded\n"
71 "Input line too long"
72 "No file|No current filename"
73 " [Read only]"
74 " [Not edited]"
75 " [Modified]"
76 "No file "
77 " line %d of %d --%ld%%--"
78 "Pattern too long"
79 "Argument buffer overflow"
80 "No alternate filename@to substitute for #"
81 "No current filename@to substitute for %%"
82 "Can't make pipe to glob"
83 "Can't fork to do glob"
84 "Arg list too long"
85 "Arg list too long"
86 "No match"
87 "Missing filename"
88 "Ambiguous|Too many file names"
89 "Filename too long"
90 " [New file]"
91 " Block special file"
92 " Teletype"
93 " Character special file"
94 " Directory"
95 " Socket"
96 " Named pipe"
97 " Executable"
98 " Compressed Data"
99 " ELF object"
100 " Archive"
101 " Non-ascii file"
102 " [Read only]"
103 " %d/%d"
104 " %d line%s, %d character%s"
105 " ("
106 "%d null"
107 ", "
108 "%d non-ASCII"
109 "Write forms are 'w' and 'w>>'"
110 "No file|No current filename"
$quote #
111 # File exists| File exists - use "w! %s" to overwrite#
$quote "
112 " File is read only"
113 " File is read only"
$quote #
114 # Use "w!" to write partial buffer#
$quote "
115 " [New file]"
116 " [Existing file]"
117 " [Incomplete last line]"
118 " Line too long"
119 "Too many nested sources"
120 "Open and visual must be used interactively"
121 "Global within global@not allowed"
122 "Global needs re|Missing regular expression for global"
123 "Global command too long"
124 "substitution loop"
125 "Fail|Substitute pattern match failed"
126 "Substitute needs re|Missing regular expression for substitute"
127 "No previous re|No previous regular expression"
128 "No previous substitute re|No previous substitute to repeat"
129 "Replacement pattern too long@- limit 256 characters"
130 "Line overflow@in substitute"
131 "%d subs|%d substitutions"
132 " on %d lines"
133 "Regular expressions cannot be delimited by letters or digits"
134 "No previous scan re|No previous scanning regular expression"
135 "No previous substitute re|No previous substitute regular expression"
136 "Badly formed re|Regular expression \\ must be followed by / or ?"
137 "No previous re|No previous regular expression"
138 "Missing closing delimiter@for regular expression"
139 "Re too complex|Regular expression too complicated"
140 "Unmatched \\(|More \\('s than \\)'s in regular expression"
141 "Awash in \\('s!|Too many \\('d subexressions in a regular expression"
142 "Extra \\)|More \\)'s than \\('s in regular expression"
143 "Bad number|Bad number in regular expression"
144 "Range endpoint too large|Range endpoint too large in regular expression"
145 "More than 2 numbers given in \\{~\\}"
146 "} expected after \\"
147 "First number exceeds second in \\{~\\}"
$quote
148 "\\digit" out of range
$quote "
149 "Replacement pattern contains &@- cannot use in re"
150 "Replacement pattern contains \\d@- cannot use in re"
151 "Illegal *|Can't * a \\( ... \\) in regular expression")
152 "Illegal *|Can't * a \\n in regular expression"
153 "Bad character class|Empty character class '[]' or '[^]' cannot match"
154 "Missing ]"
155 "No newlines in re's|Can't escape newlines into regular expressions"
156 "Bad \\n|\\n in regular expression with n greater than the number of \\('s"
157 "Badly formed re|Missing closing delimiter for regular expression"
158 "Re internal error"
159 "%s: No such option@- 'set all' gives all option values"
160 "Option %s is not a toggle"
161 "Missing =@in assignment to option %s"
162 "Digits required@after ="
163 "String too long@in option assignment"
164 "Can't change type of terminal from within open/visual"
165 "%s%s"
166 ""
167 "no"
168 "%s=%d"
169 "%s=%s"
170 "%d lines"
171 " %c%s"
172 "Nonzero address required@on this command"
173 "No lines@in the buffer"
174 "more "
175 "fewer "
176 ""
177 "%d %slines@in file after %s"
178 ""
179 "s"
180 "Out of memory@saving lines for undo - try using ed"
181 "emt trap, _ovno is %d @ - try again"
182 "\nInterrupt"
183 " Tmp file too large"
184 " Tmp file too large"
185 " Tmp file too large"
186 "Out of register space (ugh)"
187 "Nothing in register %c"
188 "Can't put partial line inside macro"
189 "Nothing in register %c"
190 "Register too long@to fit in memory"
191 "%s: Unknown terminal type"
192 "Incomplete shell escape command@- use 'shell' to get a shell"
193 "Command too long"
194 "No previous command@to substitute for !"
195 "No alternate filename@to substitute for #"
196 "No filename@to substitute for %%"
197 "[No write]|[No write since last change]"
198 "No previous command@to repeat"
199 "Can't make pipe for filter"
200 "No more processes"
201 "No %s!\n"
202 "Can't make pipe"
203 "No more processes"
204 " Can't make pipe for recovery"
205 " Can't fork to execute recovery"
206 " No recovery routine"
207 "Fail|Pattern not found on addressed line"
208 "Can't use open/visual unless open option is set"
209 "Recursive open/visual not allowed"
210 "[Using open mode]"
211 "Visual needs addressible cursor or upline capability"
212 Can't use visual on a terminal which overstrikes"
213 "Visual requires clear screen capability"
214 "Visual requires scrolling"
215 "Screen too large for internal buffer"
216 "Don't know enough about your terminal to use %s"
217 "Terminal too wide"
218 "Screen too large"
219 "Internal error: vscroll"
220 "No lines in buffer"
221 "Internal error: vredraw"
222 "Input read error"
223 "%d %sline"
224 "Macro too long@ - maybe recursive?"
225 "Infinite macro loop"
226 "Q gets ex command mode, :q leaves vi"
227 " "
228 "AAPPEND MODE"
229 "CCHANGE MODE"
230 "OOPEN MODE"
231 "RREPLACE MODE"
232 "rREPLACE 1 CHAR"
233 "IINSERT MODE"
234 "Infinite macro loop"
235 "Line too long"
236 "Line too long"
237 "Internal error: vclreol"
238 "Internal error: vgoto"
239 "Line too long for open"
240 "Line too long"
241 "No memory pool"
242 "Memory pool exhausted"
243 "failed to memory map anonymous area"
244 "failed to open /dev/zero"
245 "failed to memory map /dev/zero"
246 "chunk of memory already in free list"
247 "out of memory"
248 "(null pointer)"
249 "y"
$ exrecover
$set 2
1 " Wrong number of arguments to exrecover"
2 " [Dated: %s"
3 ", newest of %d saved]"
4 "]"
5 " Not enough core for lines"
6 "No files saved.\n"
7 "On %s at "
$quote #
8 # saved %d lines of file "%s"\n#
$quote "
9 " File not found"
10 " [Lost line(s):"
11 " %d"
12 "-%d"
13 " [Lost line(s):"
14 " %d"
15 "-%d"
16 "]"
17 " Tmp file too large"
$ expreserve
$set 3
1 "NOT super user\n"
2 "the system went down"
3 "the editor was killed"
4 "Subject: editor saved ``LOST''\n"
5 "You were editing a file without a name\n"
6 "at <%s> on the machine ``%s'' when %s.\n"
$quote #
7 #Since the file had no name, it has been named "LOST".\n#
$quote "
8 "Subject: editor saved ``%s''\n"
$quote #
9 #You were editing the file "%s"\n#
$quote "
10 "at <%s> on the machine ``%s''\n"
11 "when %s.\n"
12 "\nYou can retrieve most of your changes to this file\n"
$quote #
13 #using the "recover" command of the editor.\n#
14 #An easy way to do this is to give the command "vi -r %s".\n#
15 #This method also works using "ex" and "edit".\n#
$quote "
16 "Buffer format error\t"
17 "Buffer read error"
18 "Can't find a name\t"
/ports/trunk/editors/exvi/config.h
0,0 → 1,146
/*
* 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.
*
* @(#)config.h 1.12 (gritter) 2/19/05
*/
 
/*
* Configurable settings for the ex editor.
*/
 
/*
* Maximum screen size in visual mode.
*
* Because the routine "alloca" is not portable, TUBESIZE
* bytes are allocated on the stack each time you go into visual
* and then never freed by the system. Thus if you have no terminals
* which are larger than 24 * 80 you may well want to make TUBESIZE
* smaller. TUBECOLS should stay at 160 at least since this defines
* the maximum length of opening on hardcopies and allows two lines
* of open on terminals like adm3's (glass tty's) where it switches
* to pseudo hardcopy mode when a line gets longer than 80 characters.
*/
#ifndef VMUNIX
#define TUBELINES 70 /* Number of screen lines for visual */
#define TUBECOLS 160 /* Number of screen columns for visual */
#define TUBESIZE 6000 /* Maximum screen size for visual */
#else /* VMUNIX */
#define TUBELINES 100
#define TUBECOLS 160
#define TUBESIZE 16000
#endif /* VMUNIX */
 
/*
* Various buffer sizes.
*/
#ifndef VMUNIX
#define ESIZE 128 /* Regular expression buffer size */
#define RHSSIZE 256 /* Size of rhs of substitute */
#define TAGSIZE 128 /* Tag length */
#define ONMSZ 64 /* Option name size */
#else /* VMUNIX */
#define ESIZE 1024
#define RHSSIZE 512
#define TAGSIZE 256
#define ONMSZ 256
#endif /* VMUNIX */
 
/*
* The following types are usually predefined on modern platforms; it
* is only necessary to define them manually if compilation errors occur.
*/
 
/*
* The intptr_t type was introduced by SUSv2 and C99. It is a signed
* integer type capable of holding pointers:
*
* sizeof(intptr_t) == sizeof(void *).
*
* Type Environment Typical systems
* int IP16 PDP11, 80286
* int ILP32 Most VAX, M68k, IA32, SPARC
* long LP32 Some IA32 and M68k
* long LP64 64 bit mode of IA64, SPARC v9, and Alpha
*
* The argument to the sbrk() system call has this type.
*/
#ifdef notdef
typedef int intptr_t;
#endif
 
/*
* The ssize_t type should be the same as the return type of read()
* and write().
*/
#ifdef notdef
typedef int ssize_t;
#endif
/ports/trunk/editors/exvi/ex_vmain.c
0,0 → 1,1442
/*
* 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_vmain.c 1.29 (gritter) 2/17/05";
#endif
#endif
 
/* from ex_vmain.c 7.7 (Berkeley) 6/7/85 */
 
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
 
/*
* This is the main routine for visual.
* We here decode the count and possible named buffer specification
* preceding a command and interpret a few of the commands.
* Commands which involve a target (i.e. an operator) are decoded
* in the routine operate in ex_voperate.c.
*/
 
#define forbid(a) { if (a) goto fonfon; }
 
void
vmain(void)
{
int c, cnt, i;
cell esave[TUBECOLS];
char *oglobp;
short d;
line *addr;
int ind, nlput;
int shouldpo = 0;
int onumber = 0, olist = 0;
void (*OPline)(int) = NULL;
int (*OPutchar)(int) = NULL;
 
CLOBBGRD(c);
CLOBBGRD(cnt);
CLOBBGRD(i);
CLOBBGRD(oglobp);
CLOBBGRD(addr);
CLOBBGRD(shouldpo);
CLOBBGRD(onumber);
CLOBBGRD(olist);
CLOBBGRD(OPline);
CLOBBGRD(OPutchar);
 
vch_mac = VC_NOTINMAC;
 
/*
* If we started as a vi command (on the command line)
* then go process initial commands (recover, next or tag).
*/
if (initev) {
oglobp = globp;
globp = initev;
hadcnt = cnt = 0;
i = tchng;
addr = dot;
goto doinit;
}
 
/*
* NB:
*
* The current line is always in the line buffer linebuf,
* and the cursor at the position cursor. You should do
* a vsave() before moving off the line to make sure the disk
* copy is updated if it has changed, and a getDOT() to get
* the line back if you mung linebuf. The motion
* routines in ex_vwind.c handle most of this.
*/
for (;;) {
/*
* Decode a visual command.
* First sync the temp file if there has been a reasonable
* amount of change. Clear state for decoding of next
* command.
*/
TSYNC();
vglobp = 0;
vreg = 0;
hold = 0;
seenprompt = 1;
wcursor = 0;
Xhadcnt = hadcnt = 0;
Xcnt = cnt = 1;
splitw = 0;
if (i = holdupd) {
if (state == VISUAL)
ignore(peekkey());
holdupd = 0;
/*
if (LINE(0) < ZERO) {
vclear();
vcnt = 0;
i = 3;
}
*/
if (state != VISUAL) {
vcnt = 0;
vsave();
vrepaint(cursor);
} else if (i == 3)
vredraw(WTOP);
else
vsync(WTOP);
vfixcurs();
}
 
/*
* Gobble up counts and named buffer specifications.
*/
for (;;) {
looptop:
#ifdef MDEBUG
if (trace)
fprintf(trace, "pc=%c",peekkey());
#endif
if (xisdigit(peekkey()) && peekkey() != '0') {
hadcnt = 1;
cnt = vgetcnt();
forbid (cnt <= 0);
}
if (peekkey() != '"')
break;
ignore(getkey()), c = getkey();
/*
* Buffer names be letters or digits.
* But not '0' as that is the source of
* an 'empty' named buffer spec in the routine
* kshift (see ex_temp.c).
*/
forbid (c == '0' || !xisalpha(c) && !xisdigit(c));
vreg = c;
}
reread:
/*
* Come to reread from below after some macro expansions.
* The call to map allows use of function key pads
* by performing a terminal dependent mapping of inputs.
*/
#ifdef MDEBUG
if (trace)
fprintf(trace,"pcb=%c,",peekkey());
#endif
op = getkey();
maphopcnt = 0;
do {
/*
* Keep mapping the char as long as it changes.
* This allows for double mappings, e.g., q to #,
* #1 to something else.
*/
c = op;
op = map(c,arrows);
#ifdef MDEBUG
if (trace)
fprintf(trace,"pca=%c,",c);
#endif
/*
* Maybe the mapped to char is a count. If so, we have
* to go back to the "for" to interpret it. Likewise
* for a buffer name.
*/
if ((xisdigit(c) && c!='0') || c == '"') {
ungetkey(c);
goto looptop;
}
if (!value(REMAP)) {
c = op;
break;
}
if (++maphopcnt > 256)
error(catgets(catd, 1, 225,
"Infinite macro loop"));
} while (c != op);
 
/*
* Begin to build an image of this command for possible
* later repeat in the buffer workcmd. It will be copied
* to lastcmd by the routine setLAST
* if/when completely specified.
*/
lastcp = workcmd;
if (!vglobp)
*lastcp++ = c;
 
/*
* First level command decode.
*/
if (c == ATTN)
goto case_ATTN;
switch (c) {
 
/*
* ^L Clear screen e.g. after transmission error.
*/
 
/*
* ^R Retype screen, getting rid of @ lines.
* If in open, equivalent to ^L.
* On terminals where the right arrow key sends
* ^L we make ^R act like ^L, since there is no
* way to get ^L. These terminals (adm31, tvi)
* are intelligent so ^R is useless. Soroc
* will probably foul this up, but nobody has
* one of them.
*/
case CTRL('l'):
case CTRL('r'):
if (c == CTRL('l') || (KR && *KR==CTRL('l'))) {
vclear();
vdirty(0, vcnt);
}
if (state != VISUAL) {
/*
* Get a clean line, throw away the
* memory of what is displayed now,
* and move back onto the current line.
*/
vclean();
vcnt = 0;
vmoveto(dot, cursor, 0);
continue;
}
vredraw(WTOP);
/*
* Weird glitch -- when we enter visual
* in a very small window we may end up with
* no lines on the screen because the line
* at the top is too long. This forces the screen
* to be expanded to make room for it (after
* we have printed @'s ick showing we goofed).
*/
if (vcnt == 0)
vrepaint(cursor);
vfixcurs();
continue;
 
/*
* $ Escape just cancels the current command
* with a little feedback.
*/
case ESCAPE:
beep();
continue;
 
/*
* @ Macros. Bring in the macro and put it
* in vmacbuf, point vglobp there and punt.
*/
case '@':
c = getesc();
if (c == 0)
continue;
if (c == '@')
c = lastmac;
if (xisupper(c))
c = xtolower(c);
forbid(!xislower(c));
lastmac = c;
vsave();
CATCH
char tmpbuf[BUFSIZ];
 
regbuf(c,tmpbuf,sizeof(vmacbuf));
macpush(tmpbuf, 1);
ONERR
lastmac = 0;
splitw = 0;
getDOT();
vrepaint(cursor);
continue;
ENDCATCH
vmacp = vmacbuf;
goto reread;
 
/*
* . Repeat the last (modifying) open/visual command.
*/
case '.':
/*
* Check that there was a last command, and
* take its count and named buffer unless they
* were given anew. Special case if last command
* referenced a numeric named buffer -- increment
* the number and go to a named buffer again.
* This allows a sequence like "1pu.u.u...
* to successively look for stuff in the kill chain
* much as one does in EMACS with C-Y and M-Y.
*/
forbid (lastcmd[0] == 0);
if (hadcnt)
lastcnt = cnt;
if (vreg)
lastreg = vreg;
else if (xisdigit(lastreg) && lastreg < '9')
lastreg++;
vreg = lastreg;
cnt = lastcnt;
hadcnt = lasthad;
vglobp = lastcmd;
goto reread;
 
/*
* ^U Scroll up. A count sticks around for
* future scrolls as the scroll amount.
* Attempt to hold the indentation from the
* top of the screen (in logical lines).
*
* BUG: A ^U near the bottom of the screen
* on a dumb terminal (which can't roll back)
* causes the screen to be cleared and then
* redrawn almost as it was. In this case
* one should simply move the cursor.
*/
case CTRL('u'):
if (hadcnt)
vSCROLL = cnt;
cnt = vSCROLL;
if (state == VISUAL)
ind = vcline, cnt += ind;
else
ind = 0;
vmoving = 0;
vup(cnt, ind, 1);
vnline(NOSTR);
continue;
 
/*
* ^D Scroll down. Like scroll up.
*/
case CTRL('d'):
#ifdef TRACE
if (trace)
fprintf(trace, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
#endif
if (hadcnt)
vSCROLL = cnt;
cnt = vSCROLL;
if (state == VISUAL)
ind = vcnt - vcline - 1, cnt += ind;
else
ind = 0;
vmoving = 0;
vdown(cnt, ind, 1);
#ifdef TRACE
if (trace)
fprintf(trace, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
#endif
vnline(NOSTR);
#ifdef TRACE
if (trace)
fprintf(trace, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
#endif
continue;
 
/*
* ^E Glitch the screen down (one) line.
* Cursor left on same line in file.
*/
case CTRL('e'):
if (state != VISUAL)
continue;
if (!hadcnt)
cnt = 1;
/* Bottom line of file already on screen */
forbid(lineDOL()-lineDOT() <= vcnt-1-vcline);
ind = vcnt - vcline - 1 + cnt;
vdown(ind, ind, 1);
vnline(cursor);
continue;
 
/*
* ^Y Like ^E but up
*/
case CTRL('y'):
if (state != VISUAL)
continue;
if (!hadcnt)
cnt = 1;
forbid(lineDOT()-1<=vcline); /* line 1 already there */
ind = vcline + cnt;
vup(ind, ind, 1);
vnline(cursor);
continue;
 
 
/*
* m Mark position in mark register given
* by following letter. Return is
* accomplished via ' or `; former
* to beginning of line where mark
* was set, latter to column where marked.
*/
case 'm':
/*
* Getesc is generally used when a character
* is read as a latter part of a command
* to allow one to hit rubout/escape to cancel
* what you have typed so far. These characters
* are mapped to 0 by the subroutine.
*/
c = getesc();
if (c == 0)
continue;
 
/*
* Markreg checks that argument is a letter
* and also maps ' and ` to the end of the range
* to allow '' or `` to reference the previous
* context mark.
*/
c = markreg(c);
forbid (c == 0);
vsave();
names[c - 'a'] = (*dot &~ 01);
ncols[c - 'a'] = cursor;
anymarks = 1;
continue;
 
/*
* ^F Window forwards, with 2 lines of continuity.
* Count repeats.
*/
case CTRL('f'):
vsave();
if (vcnt > 2) {
addr = dot + (vcnt - vcline) - 2 + (cnt-1)*basWLINES;
forbid(addr > dol);
dot = (line*)addr;
vcnt = vcline = 0;
}
vzop(0, 0, '+');
continue;
 
/*
* ^B Window backwards, with 2 lines of continuity.
* Inverse of ^F.
*/
case CTRL('b'):
vsave();
if (one + vcline != dot && vcnt > 2) {
addr = dot - vcline + 2 - (cnt-1)*basWLINES;
forbid (addr <= zero);
dot = (line*)addr;
vcnt = vcline = 0;
}
vzop(0, 0, '^');
continue;
 
/*
* z Screen adjustment, taking a following character:
* z<CR> current line to top
* z<NL> like z<CR>
* z- current line to bottom
* also z+, z^ like ^F and ^B.
* A preceding count is line to use rather
* than current line. A count between z and
* specifier character changes the screen size
* for the redraw.
*
*/
case 'z':
if (state == VISUAL) {
i = vgetcnt();
if (i > 0)
vsetsiz(i);
c = getesc();
if (c == 0)
continue;
}
vsave();
vzop(hadcnt, cnt, c);
continue;
 
/*
* Y Yank lines, abbreviation for y_ or yy.
* Yanked lines can be put later if no
* changes intervene, or can be put in named
* buffers and put anytime in this session.
*/
case 'Y':
ungetkey('_');
c = 'y';
break;
 
/*
* J Join lines, 2 by default. Count is number
* of lines to join (no join operator sorry.)
*/
case 'J':
forbid (dot == dol);
if (cnt == 1)
cnt = 2;
if (cnt > (i = dol - dot + 1))
cnt = i;
vsave();
vmacchng(1);
setLAST();
cursor = strend(linebuf);
vremote(cnt, join, 0);
notenam = "join";
vmoving = 0;
killU();
vreplace(vcline, cnt, 1);
if (!*cursor && cursor > linebuf)
cursor += skipleft(linebuf, cursor);
if (notecnt == 2)
notecnt = 0;
vrepaint(cursor);
continue;
 
/*
* S Substitute text for whole lines, abbrev for c_.
* Count is number of lines to change.
*/
case 'S':
ungetkey('_');
c = 'c';
break;
 
/*
* O Create a new line above current and accept new
* input text, to an escape, there.
* A count specifies, for dumb terminals when
* slowopen is not set, the number of physical
* line space to open on the screen.
*
* o Like O, but opens lines below.
*/
case 'O':
case 'o':
vmacchng(1);
voOpen(c, cnt);
continue;
 
/*
* C Change text to end of line, short for c$.
*/
case 'C':
if (*cursor) {
ungetkey('$'), c = 'c';
break;
}
goto appnd;
 
/*
* ~ Switch case of letter under cursor
*/
case '~':
vswitch(cnt);
continue;
 
 
/*
* A Append at end of line, short for $a.
*/
case 'A':
operate('$', 1);
appnd:
c = 'a';
/* fall into ... */
 
/*
* a Appends text after cursor. Text can continue
* through arbitrary number of lines.
*/
case 'a':
if (*cursor) {
if (state == HARDOPEN) {
int c, n;
nextc(c, cursor, n);
putchar(c);
cursor += n;
} else
cursor += skipright(linebuf, cursor);
}
goto insrt;
 
/*
* I Insert at beginning of whitespace of line,
* short for ^i.
*/
case 'I':
operate('^', 1);
c = 'i';
/* fall into ... */
 
/*
* R Replace characters, one for one, by input
* (logically), like repeated r commands.
*
* BUG: This is like the typeover mode of many other
* editors, and is only rarely useful. Its
* implementation is a hack in a low level
* routine and it doesn't work very well, e.g.
* you can't move around within a R, etc.
*/
case 'R':
/* fall into... */
 
/*
* i Insert text to an escape in the buffer.
* Text is arbitrary. This command reminds of
* the i command in bare teco.
*/
case 'i':
insrt:
/*
* Common code for all the insertion commands.
* Save for redo, position cursor, prepare for append
* at command and in visual undo. Note that nothing
* is doomed, unless R when all is, and save the
* current line in a the undo temporary buffer.
*/
vmacchng(1);
setLAST();
vcursat(cursor);
prepapp();
vnoapp();
doomed = c == 'R' ? 10000 : 0;
if(FIXUNDO)
vundkind = VCHNG;
vmoving = 0;
CP(vutmp, linebuf);
 
/*
* If this is a repeated command, then suppress
* fake insert mode on dumb terminals which looks
* ridiculous and wastes lots of time even at 9600B.
*/
if (vglobp)
hold = HOLDQIK;
vappend(c, cnt, 0);
continue;
 
/*
* ^? An attention, normally a ^?, just beeps.
* If you are a vi command within ex, then
* two ATTN's will drop you back to command mode.
*/
case_ATTN:
beep();
if (initev || peekkey() != ATTN)
continue;
/* fall into... */
 
/*
* ^\ A quit always gets command mode.
*/
case QUIT:
/*
* Have to be careful if we were called
* g/xxx/vi
* since a return will just start up again.
* So we simulate an interrupt.
*/
if (inglobal)
onintr(SIGINT);
/* fall into... */
 
#ifdef notdef
/*
* q Quit back to command mode, unless called as
* vi on command line in which case dont do it
*/
case 'q': /* quit */
if (initev) {
vsave();
CATCH
error(catgets(catd, 1, 226,
"Q gets ex command mode, :q leaves vi"));
ENDCATCH
splitw = 0;
getDOT();
vrepaint(cursor);
continue;
}
#endif
/* fall into... */
 
/*
* Q Is like q, but always gets to command mode
* even if command line invocation was as vi.
*/
case 'Q':
vsave();
/*
* 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 */
}
return;
 
 
/*
* ZZ Like :x
*/
case 'Z':
forbid(getkey() != 'Z');
oglobp = globp;
globp = "x";
vclrech(0);
goto gogo;
/*
* P Put back text before cursor or before current
* line. If text was whole lines goes back
* as whole lines. If part of a single line
* or parts of whole lines splits up current
* line to form many new lines.
* May specify a named buffer, or the delete
* saving buffers 1-9.
*
* p Like P but after rather than before.
*/
case 'P':
case 'p':
vmoving = 0;
#ifdef notdef
forbid (!vreg && value(UNDOMACRO) && inopen < 0);
#endif
/*
* If previous delete was partial line, use an
* append or insert to put it back so as to
* use insert mode on intelligent terminals.
*/
if (!vreg && DEL[0]) {
forbid ((DEL[0] & (QUOTE|TRIM)) == OVERBUF);
vglobp = DEL;
ungetkey(c == 'p' ? 'a' : 'i');
goto reread;
}
 
/*
* If a register wasn't specified, then make
* sure there is something to put back.
*/
forbid (!vreg && unddol == dol);
/*
* 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);
vsave();
vmacchng(1);
setLAST();
i = 0;
if (vreg && partreg(vreg) || !vreg && pkill[0]) {
/*
* Restoring multiple lines which were partial
* lines; will leave cursor in middle
* of line after shoving restored text in to
* split the current line.
*/
i++;
if (c == 'p' && *cursor)
cursor += skipright(linebuf, cursor);
} else {
/*
* In whole line case, have to back up dot
* for P; also want to clear cursor so
* cursor will eventually be positioned
* at the beginning of the first put line.
*/
cursor = 0;
if (c == 'P') {
dot--, vcline--;
c = 'p';
}
}
killU();
 
/*
* The call to putreg can potentially
* bomb since there may be nothing in a named buffer.
* We thus put a catch in here. If we didn't and
* there was an error we would end up in command mode.
*/
addr = dol; /* old dol */
CATCH
vremote(1, vreg ? putreg : put, vreg);
ONERR
if (vreg == -1) {
splitw = 0;
if (op == 'P')
dot++, vcline++;
goto pfixup;
}
ENDCATCH
splitw = 0;
nlput = dol - addr + 1;
if (!i) {
/*
* Increment undap1, undap2 to make up
* for their incorrect initialization in the
* routine vremote before calling put/putreg.
*/
if (FIXUNDO)
undap1++, undap2++;
vcline++;
nlput--;
 
/*
* After a put want current line first line,
* and dot was made the last line put in code
* run so far. This is why we increment vcline
* above and decrease dot here.
*/
dot -= nlput - 1;
}
#ifdef TRACE
if (trace)
fprintf(trace, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline, i, nlput, lineno(undap1), lineno(undap2), lineno(dot));
#endif
vreplace(vcline, i, nlput);
if (state != VISUAL) {
/*
* Special case in open mode.
* Force action on the screen when a single
* line is put even if it is identical to
* the current line, e.g. on YP; otherwise
* you can't tell anything happened.
*/
vjumpto(dot, cursor, '.');
continue;
}
pfixup:
vrepaint(cursor);
vfixcurs();
continue;
 
/*
* ^^ Return to previous file.
* Like a :e #, and thus can be used after a
* "No Write" diagnostic.
*/
case CTRL('^'):
forbid (hadcnt);
vsave();
ckaw();
oglobp = globp;
if (value(AUTOWRITE))
globp = "e! #";
else
globp = "e #";
goto gogo;
 
/*
* ^] Takes word after cursor as tag, and then does
* tag command. Read ``go right to''.
*/
case CTRL(']'):
grabtag();
oglobp = globp;
globp = "tag";
goto gogo;
 
/*
* & Like :&
*/
case '&':
oglobp = globp;
globp = "&";
goto gogo;
/*
* ^G Bring up a status line at the bottom of
* the screen, like a :file command.
*
* BUG: Was ^S but doesn't work in cbreak mode
*/
case CTRL('g'):
oglobp = globp;
globp = "file";
gogo:
addr = dot;
vsave();
goto doinit;
 
#ifdef SIGTSTP
/*
* ^Z: suspend editor session and temporarily return
* to shell. Only works with Berkeley/IIASA process
* control in kernel.
*/
case CTRL('z'):
forbid(dosusp == 0 || !ldisc);
vsave();
oglobp = globp;
globp = "stop";
goto gogo;
#endif
 
/*
* : Read a command from the echo area and
* execute it in command mode.
*/
case ':':
forbid (hadcnt);
vsave();
i = tchng;
addr = dot;
if (readecho(c)) {
esave[0] = 0;
goto fixup;
}
getDOT();
/*
* Use the visual undo buffer to store the global
* string for command mode, since it is idle right now.
*/
oglobp = globp;
CP(vutmp, genbuf+1);
globp = vutmp;
doinit:
esave[0] = 0;
fixech();
 
/*
* Have to finagle around not to lose last
* character after this command (when run from ex
* command mode). This is clumsy.
*/
d = peekc; ungetchar(0);
if (shouldpo) {
/*
* So after a "Hit return..." ":", we do
* another "Hit return..." the next time
*/
pofix();
shouldpo = 0;
}
CATCH
/*
* Save old values of options so we can
* notice when they change; switch into
* cooked mode so we are interruptible.
*/
onumber = value(NUMBER);
olist = value(LIST);
OPline = Pline;
OPutchar = Putchar;
commands(1, 1);
if (dot == zero && dol > zero)
dot = one;
ONERR
copy(esave, vtube[WECHO],
TUBECOLS * sizeof *esave);
ENDCATCH
fixol();
Pline = OPline;
Putchar = OPutchar;
ungetchar(d);
if (globp && tflag < 0) {
tflag = 0;
goto doinit;
}
globp = oglobp;
 
/*
* If we ended up with no lines in the buffer, make
* a line, and don't consider the buffer changed.
*/
if (dot == zero) {
fixzero();
/*synced();*/
}
splitw = 0;
 
/*
* Special case: did list/number options change?
*/
if (onumber != value(NUMBER))
setnumb(value(NUMBER));
if (olist != value(LIST))
setlist(value(LIST));
 
fixup:
/*
* If a change occurred, other than
* a write which clears changes, then
* we should allow an undo even if .
* didn't move.
*
* BUG: You can make this wrong by
* tricking around with multiple commands
* on one line of : escape, and including
* a write command there, but its not
* worth worrying about.
*/
if (FIXUNDO && tchng && tchng != i)
vundkind = VMANY, cursor = 0;
 
/*
* If we are about to do another :, hold off
* updating of screen.
*/
if (vcnt < 0 && Peekkey == ':') {
getDOT();
shouldpo = 1;
continue;
}
shouldpo = 0;
 
/*
* In the case where the file being edited is
* new; e.g. if the initial state hasn't been
* saved yet, then do so now.
*/
if (unddol == truedol) {
vundkind = VNONE;
Vlines = lineDOL();
if (!inglobal)
savevis();
addr = zero;
vcnt = 0;
if (esave[0] == 0)
copy(esave, vtube[WECHO],
TUBECOLS * sizeof *esave);
}
 
/*
* If the current line moved reset the cursor position.
*/
if (dot != addr) {
vmoving = 0;
cursor = 0;
}
 
/*
* If current line is not on screen or if we are
* in open mode and . moved, then redraw.
*/
i = vcline + (dot - addr);
if (i < 0 || i >= vcnt && i >= -vcnt || state != VISUAL && dot != addr) {
if (state == CRTOPEN)
vup1();
if (vcnt > 0)
vcnt = 0;
vjumpto(dot, (char *) 0, '.');
} else {
/*
* Current line IS on screen.
* If we did a [Hit return...] then
* restore vcnt and clear screen if in visual
*/
vcline = i;
if (vcnt < 0) {
vcnt = -vcnt;
if (state == VISUAL)
vclear();
else if (state == CRTOPEN) {
vcnt = 0;
}
}
 
/*
* Limit max value of vcnt based on $
*/
i = vcline + lineDOL() - lineDOT() + 1;
if (i < vcnt)
vcnt = i;
/*
* Dirty and repaint.
*/
vdirty(0, TLINES);
vrepaint(cursor);
}
 
/*
* If in visual, put back the echo area
* if it was clobberred.
*/
if (state == VISUAL) {
int sdc = destcol, sdl = destline;
 
splitw++;
vigoto(WECHO, 0);
for (i = 0; i < TUBECOLS - 1; i++) {
if (esave[i] == 0)
break;
vputchar(esave[i]);
}
splitw = 0;
vgoto(sdl, sdc);
}
continue;
 
/*
* u undo the last changing command.
*/
case 'u':
vundo(1);
continue;
 
/*
* U restore current line to initial state.
*/
case 'U':
vUndo();
continue;
 
fonfon:
beep();
vmacp = 0;
inopen = 1; /* might have been -1 */
continue;
}
 
/*
* Rest of commands are decoded by the operate
* routine.
*/
operate(c, cnt);
}
}
 
/*
* Grab the word after the cursor so we can look for it as a tag.
*/
void
grabtag(void)
{
register char *cp, *dp;
 
cp = vpastwh(cursor);
if (*cp) {
dp = lasttag;
do {
if (dp < &lasttag[sizeof lasttag - 2])
*dp++ = *cp;
cp++;
} while (isalpha(*cp&0377) || isdigit(*cp&0377)
|| *cp == '_'
#ifdef LISPCODE
|| (value(LISP) && *cp == '-')
#endif /* LISPCODE */
);
*dp++ = 0;
}
}
 
/*
* Before appending lines, set up addr1 and
* the command mode undo information.
*/
void
prepapp(void)
{
 
addr1 = dot;
deletenone();
addr1++;
appendnone();
}
 
/*
* Execute function f with the address bounds addr1
* and addr2 surrounding cnt lines starting at dot.
*/
void
vremote(int cnt, void (*f)(int), int arg)
{
register int oing = inglobal;
 
addr1 = dot;
addr2 = dot + cnt - 1;
inglobal = 0;
if (FIXUNDO)
undap1 = undap2 = dot;
(*f)(arg);
inglobal = oing;
if (FIXUNDO)
vundkind = VMANY;
vmcurs = 0;
}
 
/*
* Save the current contents of linebuf, if it has changed.
*/
void
vsave(void)
{
char temp[LBSIZE];
 
CP(temp, linebuf);
if (FIXUNDO && vundkind == VCHNG || vundkind == VCAPU) {
/*
* If the undo state is saved in the temporary buffer
* vutmp, then we sync this into the temp file so that
* we will be able to undo even after we have moved off
* the line. It would be possible to associate a line
* with vutmp but we assume that vutmp is only associated
* with line dot (e.g. in case ':') above, so beware.
*/
prepapp();
CP(linebuf, vutmp);
putmark(dot);
vremote(1, yank, 0);
vundkind = VMCHNG;
notecnt = 0;
undkind = UNDCHANGE;
}
/*
* Get the line out of the temp file and do nothing if it hasn't
* changed. This may seem like a loss, but the line will
* almost always be in a read buffer so this may well avoid disk i/o.
*/
getDOT();
if (strcmp(linebuf, temp) == 0)
return;
strcLIN(temp);
putmark(dot);
}
 
#undef forbid
#define forbid(a) if (a) { beep(); return; }
 
/*
* Do a z operation.
* Code here is rather long, and very uninteresting.
*/
void
vzop(int hadcnt, int cnt, register int c)
{
register line *addr;
 
if (state != VISUAL) {
/*
* Z from open; always like a z=.
* This code is a mess and should be cleaned up.
*/
vmoveitup(1, 1);
vgoto(outline, 0);
ostop(normf);
setoutt();
addr2 = dot;
vclear();
destline = WECHO;
zop2(Xhadcnt ? Xcnt : value(WINDOW) - 1, '=');
if (state == CRTOPEN)
putnl();
putNFL();
termreset();
Outchar = vputchar;
ignore(ostart());
vcnt = 0;
outline = destline = 0;
vjumpto(dot, cursor, 0);
return;
}
if (hadcnt) {
addr = zero + cnt;
if (addr < one)
addr = one;
if (addr > dol)
addr = dol;
markit(addr);
} else
switch (c) {
 
case '+':
addr = dot + vcnt - vcline;
break;
 
case '^':
addr = dot - vcline - 1;
forbid (addr < one);
c = '-';
break;
 
default:
addr = dot;
break;
}
switch (c) {
 
case '.':
case '-':
break;
 
case '^':
forbid (addr <= one);
break;
 
case '+':
forbid (addr >= dol);
/* fall into ... */
 
case CR:
case NL:
c = CR;
break;
 
default:
beep();
return;
}
vmoving = 0;
vjumpto(addr, NOSTR, c);
}
 
cell *
str2cell(cell *dst, register char *src)
{
register cell *cp = dst;
 
#ifdef MB
if (mb_cur_max > 1) {
int c, n;
do {
nextc(c, src, n);
src += n;
*cp++ = c;
} while (src[-n]);
} else
#endif /* MB */
while (*cp++ = *src++ & 0377);
return dst;
}
 
char *
cell2str(char *dst, register cell *src)
{
register char *cp = dst;
 
while (*cp++ = *src++);
return dst;
}
 
cell *
cellcpy(cell *dst, register cell *src)
{
register cell *cp = dst;
 
while (*cp++ = *src++);
return dst;
}
 
size_t
cellen(register cell *cp)
{
register size_t sz = 0;
 
while (*cp++)
sz++;
return sz;
}
 
cell *
cellcat(cell *dst, register cell *src)
{
register cell *cp = dst;
 
while (*cp)
cp++;
cellcpy(cp, src);
return dst;
}
/ports/trunk/editors/exvi/ex_vops2.c
0,0 → 1,1097
/*
* 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_vops2.c 1.34 (gritter) 1/12/05";
#endif
#endif
 
/* from ex_vops2.c 6.8 (Berkeley) 6/7/85 */
 
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
 
/*
* Low level routines for operations sequences,
* and mostly, insert mode (and a subroutine
* to read an input line, including in the echo area.)
*/
extern char *vUA1, *vUA2; /* mjm: extern; also in ex_vops.c */
extern char *vUD1, *vUD2; /* mjm: extern; also in ex_vops.c */
 
/*
* Obleeperate characters in hardcopy
* open with \'s.
*/
void
bleep(register int i, char *cp)
{
 
i -= column(cp);
do
putchar('\\' | QUOTE);
while (--i >= 0);
rubble = 1;
}
 
/*
* Common code for middle part of delete
* and change operating on parts of lines.
*/
int
vdcMID(void)
{
register char *cp;
 
squish();
setLAST();
if (FIXUNDO)
vundkind = VCHNG, CP(vutmp, linebuf);
if (wcursor < cursor)
cp = wcursor, wcursor = cursor, cursor = cp;
vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
return (column(wcursor + skipleft(linebuf, wcursor)));
}
 
/*
* Take text from linebuf and stick it
* in the VBSIZE buffer BUF. Used to save
* deleted text of part of line.
*/
void
takeout(cell *BUF)
{
register char *cp;
 
if (wcursor < linebuf)
wcursor = linebuf;
if (cursor == wcursor) {
beep();
return;
}
if (wcursor < cursor) {
cp = wcursor;
wcursor = cursor;
cursor = cp;
}
setBUF(BUF);
if ((BUF[0] & (QUOTE|TRIM)) == OVERBUF)
beep();
}
 
/*
* Are we at the end of the printed representation of the
* line? Used internally in hardcopy open.
*/
int
ateopr(void)
{
register int i, c;
register cell *cp = vtube[destline] + destcol;
 
for (i = WCOLS - destcol; i > 0; i--) {
c = *cp++;
if (c == 0)
return (1);
if (c != ' ' && (c & QUOTE) == 0)
return (0);
}
return (1);
}
 
void
showmode(int mode)
{
int sdc = destcol, sdl = destline;
char *ocurs, *str;
 
if (value(SHOWMODE) == 0 || TCOLUMNS <= 20 || state == ONEOPEN
|| state == HARDOPEN || vmacp != NULL)
return;
ocurs = cursor;
fixech();
vgoto(WECHO, TCOLUMNS - 20);
switch (mode) {
case 0: str = catgets(catd, 1, 227,
" ");
break;
case 'A': /*FALLTHROUGH*/
case 'a': str = catgets(catd, 1, 228,
"AAPPEND MODE");
break;
case 'C': /*FALLTHROUGH*/
case 'c': str = catgets(catd, 1, 229,
"CCHANGE MODE");
break;
case 'O': /*FALLTHROUGH*/
case 'o': str = catgets(catd, 1, 230,
"OOPEN MODE");
break;
case 'R': str = catgets(catd, 1, 231,
"RREPLACE MODE");
break;
case 'r': str = catgets(catd, 1, 232,
"rREPLACE 1 CHAR");
break;
default: str = catgets(catd, 1, 233,
"IINSERT MODE");
}
if (value(TERSE))
putchar(str[0]);
else
printf(&str[1]);
vgoto(sdl, sdc);
cursor = ocurs;
splitw = 0;
}
 
/*
* Append.
*
* This routine handles the top level append, doing work
* as each new line comes in, and arranging repeatability.
* It also handles append with repeat counts, and calculation
* of autoindents for new lines.
*/
bool vaifirst;
bool gobbled;
char *ogcursor;
 
/*
* The addtext() and addto() routines combined, accepting a single
* cell character.
*/
void
addc(cell c)
{
register cell *cp = INS;
 
if (vglobp)
return;
if ((cp[0] & (QUOTE|TRIM)) != OVERBUF) {
if (cellen(cp) + 2 >= VBSIZE) {
cp[0] = OVERBUF;
lastcmd[0] = 0;
} else {
while (*cp)
cp++;
*cp++ = c;
*cp++ = 0;
}
}
}
 
void
vappend(int ch, int cnt, int indent)
/* int ch; /\* mjm: char --> int */
{
register int i = 0;
register char *gcursor;
bool escape;
int repcnt, savedoomed;
short oldhold = hold;
#ifdef SIGWINCH
sigset_t set, oset;
#endif
 
/*
* Before a move in hardopen when the line is dirty
* or we are in the middle of the printed representation,
* we retype the line to the left of the cursor so the
* insert looks clean.
*/
if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
rubble = 1;
gcursor = cursor;
i = *gcursor;
*gcursor = ' ';
wcursor = gcursor;
vmove(0);
*gcursor = i;
}
vaifirst = indent == 0;
 
showmode(ch);
 
/*
* Handle replace character by (eventually)
* limiting the number of input characters allowed
* in the vgetline routine.
*/
if (ch == 'r')
repcnt = 2;
else
repcnt = 0;
 
/*
* If an autoindent is specified, then
* generate a mixture of blanks to tabs to implement
* it and place the cursor after the indent.
* Text read by the vgetline routine will be placed in genbuf,
* so the indent is generated there.
*/
if (value(AUTOINDENT) && indent != 0) {
gcursor = genindent(indent);
*gcursor = 0;
vgotoCL(qcolumn(cursor + skipright(cursor, linebuf), genbuf));
} else {
gcursor = genbuf;
*gcursor = 0;
if (ch == 'o')
vfixcurs();
}
 
/*
* Prepare for undo. Pointers delimit inserted portion of line.
*/
vUA1 = vUA2 = cursor;
 
/*
* If we are not in a repeated command and a ^@ comes in
* then this means the previous inserted text.
* If there is none or it was too long to be saved,
* then beep() and also arrange to undo any damage done
* so far (e.g. if we are a change.)
*/
if ((vglobp && *vglobp == 0) || peekbr()) {
if ((INS[0] & (QUOTE|TRIM)) == OVERBUF) {
beep();
if (!splitw)
ungetkey('u');
doomed = 0;
hold = oldhold;
showmode(0);
return;
}
/*
* Unread input from INS.
* An escape will be generated at end of string.
* Hold off n^^2 type update on dumb terminals.
*/
vglobp = INS;
hold |= HOLDQIK;
} else if (vglobp == 0)
/*
* Not a repeated command, get
* a new inserted text for repeat.
*/
INS[0] = 0;
 
/*
* For wrapmargin to hack away second space after a '.'
* when the first space caused a line break we keep
* track that this happened in gobblebl, which says
* to gobble up a blank silently.
*/
gobblebl = 0;
 
#ifdef SIGWINCH
sigemptyset(&set);
sigaddset(&set, SIGWINCH);
sigprocmask(SIG_BLOCK, &set, &oset);
#endif
/*
* Text gathering loop.
* New text goes into genbuf starting at gcursor.
* cursor preserves place in linebuf where text will eventually go.
*/
if (*cursor == 0 || state == CRTOPEN)
hold |= HOLDROL;
for (;;) {
if (ch == 'r' && repcnt == 0)
escape = 0;
else {
gcursor = vgetline(repcnt, gcursor, &escape, ch);
 
/*
* After an append, stick information
* about the ^D's and ^^D's and 0^D's in
* the repeated text buffer so repeated
* inserts of stuff indented with ^D as backtab's
* can work.
*/
if (HADUP)
addc('^');
else if (HADZERO)
addc('0');
while (CDCNT > 0)
#ifndef BIT8
addc('\204'), CDCNT--;
#else
addc(OVERBUF), CDCNT--;
#endif
if (gobbled)
addc(' ');
addtext(ogcursor);
}
repcnt = 0;
 
/*
* Smash the generated and preexisting indents together
* and generate one cleanly made out of tabs and spaces
* if we are using autoindent.
*/
if (!vaifirst && value(AUTOINDENT)) {
i = fixindent(indent);
if (!HADUP)
indent = i;
gcursor = strend(genbuf);
}
 
/*
* Limit the repetition count based on maximum
* possible line length; do output implied
* by further count (> 1) and cons up the new line
* in linebuf.
*/
cnt = vmaxrep(ch, cnt);
CP(gcursor + skipright(ogcursor, gcursor), cursor);
do {
CP(cursor, genbuf);
if (cnt > 1) {
int oldhold = hold;
 
Outchar = vinschar;
hold |= HOLDQIK;
printf("%s", genbuf);
hold = oldhold;
Outchar = vputchar;
}
cursor += gcursor - genbuf;
} while (--cnt > 0);
endim();
vUA2 = cursor;
if (escape != '\n')
CP(cursor, gcursor + skipright(ogcursor, gcursor));
 
/*
* If doomed characters remain, clobber them,
* and reopen the line to get the display exact.
*/
if (state != HARDOPEN) {
DEPTH(vcline) = 0;
savedoomed = doomed;
if (doomed > 0) {
register int cind = cindent();
 
physdc(cind, cind + doomed);
doomed = 0;
}
i = vreopen(LINE(vcline), lineDOT(), vcline);
#ifdef TRACE
if (trace)
fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
#endif
if (ch == 'R')
doomed = savedoomed;
}
 
/*
* All done unless we are continuing on to another line.
*/
if (escape != '\n')
break;
 
/*
* Set up for the new line.
* First save the current line, then construct a new
* first image for the continuation line consisting
* of any new autoindent plus the pushed ahead text.
*/
showmode(0);
killU();
addc(gobblebl ? ' ' : '\n');
vsave();
cnt = 1;
if (value(AUTOINDENT)) {
#ifdef LISPCODE
if (value(LISP))
indent = lindent(dot + 1);
else
#endif
if (!HADUP && vaifirst)
indent = whitecnt(linebuf);
vaifirst = 0;
strcLIN(vpastwh(gcursor + 1));
gcursor = genindent(indent);
*gcursor = 0;
if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
gcursor = genbuf;
CP(gcursor, linebuf);
} else {
CP(genbuf, gcursor + skipright(ogcursor, gcursor));
gcursor = genbuf;
}
 
/*
* If we started out as a single line operation and are now
* turning into a multi-line change, then we had better yank
* out dot before it changes so that undo will work
* correctly later.
*/
if (FIXUNDO && vundkind == VCHNG) {
vremote(1, yank, 0);
undap1--;
}
 
/*
* Now do the append of the new line in the buffer,
* and update the display. If slowopen
* we don't do very much.
*/
vdoappend(genbuf);
vundkind = VMANYINS;
vcline++;
if (state != VISUAL)
vshow(dot, NOLINE);
else {
i += LINE(vcline - 1);
vopen(dot, i);
if (value(SLOWOPEN))
vscrap();
else
vsync1(LINE(vcline));
}
strcLIN(gcursor);
*gcursor = 0;
cursor = linebuf;
vgotoCL(qcolumn(cursor + skipleft(ogcursor, cursor), genbuf));
showmode(ch);
}
 
/*
* All done with insertion, position the cursor
* and sync the screen.
*/
showmode(0);
hold = oldhold;
if (cursor > linebuf)
cursor += skipleft(linebuf, cursor);
if (state != HARDOPEN)
vsyncCL();
else if (cursor > linebuf)
back1();
doomed = 0;
wcursor = cursor;
vmove(0);
#ifdef SIGWINCH
sigprocmask(SIG_SETMASK, &oset, NULL);
#endif
}
 
/*
* Subroutine for vgetline to back up a single character position,
* backwards around end of lines (vgoto can't hack columns which are
* less than 0 in general).
*/
void
back1(void)
{
 
vgoto(destline - 1, WCOLS + destcol - 1);
}
 
#define gappend(c) { \
int _c = c; \
xgappend(_c, &gcursor); \
}
 
static void
xgappend(int c, char **gp)
{
if (*gp >= &genbuf[MAXBSIZE-mb_cur_max-1]) {
beep();
return;
}
#ifdef MB
if (mb_cur_max > 1 && !(c & INVBIT)) {
char mb[MB_LEN_MAX];
int i, n;
n = wctomb(mb, c);
for (i = 0; i < n; i++)
*(*gp)++ = mb[i];
} else
#endif /* MB */
*(*gp)++ = c & 0377;
}
 
/*
* Get a line into genbuf after gcursor.
* Cnt limits the number of input characters
* accepted and is used for handling the replace
* single character command. Aescaped is the location
* where we stick a termination indicator (whether we
* ended with an ESCAPE or a newline/return.
*
* We do erase-kill type processing here and also
* are careful about the way we do this so that it is
* repeatable. (I.e. so that your kill doesn't happen,
* when you repeat an insert if it was escaped with \ the
* first time you did it. commch is the command character
* involved, including the prompt for readline.
*/
char *
vgetline(int cnt, char *gcursor, bool *aescaped, int commch)
{
register int c, ch;
register char *cp;
int x, y, iwhite, backsl=0;
cell *iglobp;
char cstr[2];
int (*OO)() = Outchar;
 
/*
* Clear the output state and counters
* for autoindent backwards motion (counts of ^D, etc.)
* Remember how much white space at beginning of line so
* as not to allow backspace over autoindent.
*/
*aescaped = 0;
ogcursor = gcursor;
flusho();
CDCNT = 0;
HADUP = 0;
HADZERO = 0;
gobbled = 0;
iwhite = whitecnt(genbuf);
iglobp = vglobp;
 
/*
* Carefully avoid using vinschar in the echo area.
*/
if (splitw)
Outchar = vputchar;
else {
Outchar = vinschar;
vprepins();
}
for (;;) {
backsl = 0;
if (gobblebl)
gobblebl--;
if (cnt != 0) {
cnt--;
if (cnt == 0)
goto vadone;
}
c = getkey();
if (c != ATTN)
c &= (QUOTE|TRIM);
ch = c;
maphopcnt = 0;
if (vglobp == 0 && Peekkey == 0 && commch != 'r')
while ((ch = map(c, immacs)) != c) {
c = ch;
if (!value(REMAP))
break;
if (++maphopcnt > 256)
error(catgets(catd, 1, 234,
"Infinite macro loop"));
}
if (!iglobp) {
 
/*
* Erase-kill type processing.
* Only happens if we were not reading
* from untyped input when we started.
* Map users erase to ^H, kill to -1 for switch.
*/
if (c == tty.c_cc[VERASE])
c = CTRL('h');
else if (c == tty.c_cc[VKILL])
c = -1;
if (c == ATTN)
goto case_ATTN;
switch (c) {
 
/*
* ^? Interrupt drops you back to visual
* command mode with an unread interrupt
* still in the input buffer.
*
* ^\ Quit does the same as interrupt.
* If you are a ex command rather than
* a vi command this will drop you
* back to command mode for sure.
*/
case QUIT:
case_ATTN:
ungetkey(c);
goto vadone;
 
/*
* ^H Backs up a character in the input.
*
* BUG: Can't back around line boundaries.
* This is hard because stuff has
* already been saved for repeat.
*/
case CTRL('h'):
bakchar:
cp = gcursor + skipleft(ogcursor, gcursor);
if (cp < ogcursor) {
if (splitw) {
/*
* Backspacing over readecho
* prompt. Pretend delete but
* don't beep.
*/
ungetkey(c);
goto vadone;
}
beep();
continue;
}
goto vbackup;
 
/*
* ^W Back up a white/non-white word.
*/
case CTRL('w'):
wdkind = 1;
for (cp = gcursor; cp > ogcursor
&& isspace(cp[-1]&0377); cp--)
continue;
for (c = wordch(cp - 1);
cp > ogcursor && wordof(c, cp - 1); cp--)
continue;
goto vbackup;
 
/*
* users kill Kill input on this line, back to
* the autoindent.
*/
case -1:
cp = ogcursor;
vbackup:
if (cp == gcursor) {
beep();
continue;
}
endim();
*cp = 0;
c = cindent();
vgotoCL(qcolumn(cursor +
skipleft(linebuf, cursor), genbuf));
if (doomed >= 0)
doomed += c - cindent();
gcursor = cp;
continue;
 
/*
* \ Followed by erase or kill
* maps to just the erase or kill.
*/
case '\\':
x = destcol, y = destline;
putchar('\\');
vcsync();
c = getkey();
if (c == tty.c_cc[VERASE]
|| c == tty.c_cc[VKILL])
{
vgoto(y, x);
if (doomed >= 0)
doomed++;
goto def;
}
ungetkey(c), c = '\\';
backsl = 1;
break;
 
/*
* ^Q Super quote following character
* Only ^@ is verboten (trapped at
* a lower level) and \n forces a line
* split so doesn't really go in.
*
* ^V Synonym for ^Q
*/
case CTRL('q'):
case CTRL('v'):
x = destcol, y = destline;
putchar('^');
vgoto(y, x);
c = getkey();
if (c != NL) {
if (doomed >= 0)
doomed++;
goto def;
}
break;
}
}
 
/*
* If we get a blank not in the echo area
* consider splitting the window in the wrapmargin.
*/
if (c != NL && !splitw) {
if (c == ' ' && gobblebl) {
gobbled = 1;
continue;
}
if (value(WRAPMARGIN) &&
(outcol >= OCOLUMNS - value(WRAPMARGIN) ||
backsl && outcol==0) &&
commch != 'r') {
/*
* At end of word and hit wrapmargin.
* Move the word to next line and keep going.
*/
wdkind = 1;
gappend(c);
if (backsl)
gappend(getkey());
*gcursor = 0;
/*
* Find end of previous word if we are past it.
*/
for (cp=gcursor; cp>ogcursor
&& isspace(cp[-1]&0377); cp--)
;
if (outcol+(backsl?OCOLUMNS:0) - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) {
/*
* Find beginning of previous word.
*/
for (; cp>ogcursor && !isspace(cp[-1]&0377); 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]&0377))
cp--; /* skip blank */
gobblebl = 3;
goto vbackup;
}
dontbreak:;
}
 
/*
* 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 + skipleft(ogcursor, gcursor);
for (wdtype = wordch(cp - 1);
cp > ogcursor && wordof(wdtype, cp - 1); cp--)
;
*gcursor = 0;
for (abno=0; abbrevs[abno].mapto; abno++) {
if (!abbrevs[abno].hadthis &&
eq(cp, abbrevs[abno].cap)) {
abbrevs[abno].hadthis++;
macpush(cstr, 0);
macpush(abbrevs[abno].mapto, 0);
goto vbackup;
}
}
}
 
#ifdef BIT8
if (c == OVERBUF)
goto btrp;
#endif
switch (c) {
 
/*
* ^M Except in repeat maps to \n.
*/
case CR:
if (vglobp)
goto def;
c = '\n';
/* presto chango ... */
 
/*
* \n Start new line.
*/
case NL:
*aescaped = c;
goto vadone;
 
/*
* escape End insert unless repeat and more to repeat.
*/
case ESCAPE:
if (lastvgk)
goto def;
goto vadone;
 
/*
* ^D Backtab.
* ^T Software forward tab.
*
* Unless in repeat where this means these
* were superquoted in.
*/
case CTRL('d'):
case CTRL('t'):
if (vglobp)
goto def;
/* fall into ... */
 
/*
* ^D|QUOTE Is a backtab (in a repeated command).
*/
#ifndef BIT8
case CTRL('d') | QUOTE:
#else
btrp:
#endif
*gcursor = 0;
cp = vpastwh(genbuf);
c = whitecnt(genbuf);
if (ch == CTRL('t')) {
/*
* ^t just generates new indent replacing
* current white space rounded up to soft
* tab stop increment.
*/
if (cp != gcursor)
/*
* BUG: Don't hack ^T except
* right after initial
* white space.
*/
continue;
cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1));
ogcursor = cp;
goto vbackup;
}
/*
* ^D works only if we are at the (end of) the
* generated autoindent. We count the ^D for repeat
* purposes.
*/
if (c == iwhite && c != 0)
if (cp == gcursor) {
iwhite = backtab(c);
CDCNT++;
ogcursor = cp = genindent(iwhite);
goto vbackup;
} else if (&cp[1] == gcursor &&
(*cp == '^' || *cp == '0')) {
/*
* ^^D moves to margin, then back
* to current indent on next line.
*
* 0^D moves to margin and then
* stays there.
*/
HADZERO = *cp == '0';
ogcursor = cp = genbuf;
HADUP = 1 - HADZERO;
CDCNT = 1;
endim();
back1();
vputchar(' ');
goto vbackup;
}
if (vglobp && vglobp - iglobp >= 2 &&
(vglobp[-2] == '^' || vglobp[-2] == '0')
&& gcursor == ogcursor + 1)
goto bakchar;
continue;
 
default:
/*
* Possibly discard control inputs.
*/
if (!vglobp && junk(c)) {
beep();
continue;
}
def:
if (!backsl) {
/* int cnt; */
putchar(c);
flush();
}
if (gcursor > &genbuf[LBSIZE - 2])
error(catgets(catd, 1, 235, "Line too long"));
gappend(c & TRIM);
vcsync();
if (value(SHOWMATCH) && !iglobp)
if (c == ')' || c == '}')
lsmatch(gcursor);
continue;
}
}
vadone:
*gcursor = 0;
if (Outchar != termchar)
Outchar = OO;
endim();
return (gcursor);
}
 
char *vsplitpt;
 
/*
* Append the line in buffer at lp
* to the buffer after dot.
*/
void
vdoappend(char *lp)
{
register int oing = inglobal;
 
vsplitpt = lp;
inglobal = 1;
ignore(append(vgetsplit, dot));
inglobal = oing;
}
 
/*
* Subroutine for vdoappend to pass to append.
*/
int
vgetsplit(void)
{
 
if (vsplitpt == 0)
return (EOF);
strcLIN(vsplitpt);
vsplitpt = 0;
return (0);
}
 
/*
* Vmaxrep determines the maximum repetitition factor
* allowed that will yield total line length less than
* LBSIZE characters and also does hacks for the R command.
*/
int
vmaxrep(int ch, register int cnt)
{
register int len, replen;
 
if (cnt > LBSIZE - 2)
cnt = LBSIZE - 2;
replen = strlen(genbuf);
if (ch == 'R') {
len = strlen(cursor);
if (replen < len)
len = replen;
#ifdef MB
if (mb_cur_max > 1) {
char *cp, *gp;
int c, g;
for (gp = genbuf, g = 0; *gp; g++)
gp += wskipright(genbuf, gp);
for (cp = cursor, c = 0; c < g; c++)
cp += wskipright(cursor, cp);
CP(cursor, cp);
} else
#endif /* MB */
CP(cursor, cursor + len);
vUD2 += len;
}
len = strlen(linebuf);
if (len + cnt * replen <= LBSIZE - 2)
return (cnt);
cnt = (LBSIZE - 2 - len) / replen;
if (cnt == 0) {
vsave();
error(catgets(catd, 1, 236, "Line too long"));
}
return (cnt);
}
/ports/trunk/editors/exvi/ex_vwind.c
0,0 → 1,500
/*
* 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_vwind.c 1.9 (gritter) 11/23/04";
#endif
#endif
 
/* from ex_vwind.c 7.3 (Berkeley) 6/7/85 */
 
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
 
/*
* Routines to adjust the window, showing specified lines
* in certain positions on the screen, and scrolling in both
* directions. Code here is very dependent on mode (open versus visual).
*/
 
/*
* Move in a nonlocal way to line addr.
* If it isn't on screen put it in specified context.
* New position for cursor is curs.
* Like most routines here, we vsave().
*/
void
vmoveto(register line *addr, char *curs, int context)
{
 
markit(addr);
vsave();
vjumpto(addr, curs, context);
}
 
/*
* Vjumpto is like vmoveto, but doesn't mark previous
* context or save linebuf as current line.
*/
void
vjumpto(register line *addr, char *curs, int context)
{
 
noteit(0);
if (context != 0)
vcontext(addr, context);
else
vshow(addr, NOLINE);
noteit(1);
vnline(curs);
}
 
/*
* Go up or down cnt (negative is up) to new position curs.
*/
void
vupdown(register int cnt, char *curs)
{
 
if (cnt > 0)
vdown(cnt, 0, 0);
else if (cnt < 0)
vup(-cnt, 0, 0);
if (vcnt == 0)
vrepaint(curs);
else
vnline(curs);
}
 
/*
* Go up cnt lines, afterwards preferring to be ind
* logical lines from the top of the screen.
* If scroll, then we MUST use a scroll.
* Otherwise clear and redraw if motion is far.
*/
void
vup(register int cnt, register int ind, int scroll)
{
register int i, tot;
 
if (dot == one) {
beep();
return;
}
vsave();
i = lineDOT() - 1;
if (cnt > i) {
ind -= cnt - i;
if (ind < 0)
ind = 0;
cnt = i;
}
if (!scroll && cnt <= vcline) {
vshow(dot - cnt, NOLINE);
return;
}
cnt -= vcline, dot -= vcline, vcline = 0;
if (hold & HOLDWIG)
goto contxt;
if (state == VISUAL && !AL && !SR &&
cnt <= WTOP - ZERO && vfit(dot - cnt, cnt) <= WTOP - ZERO)
goto okr;
tot = WECHO - ZERO;
if (state != VISUAL || (!AL && !SR) || (!scroll && (cnt > tot || vfit(dot - cnt, cnt) > tot / 3 + 1))) {
if (ind > basWLINES / 2)
ind = basWLINES / 3;
contxt:
vcontext(dot + ind - cnt, '.');
return;
}
okr:
vrollR(cnt);
if (scroll) {
vcline += ind, dot += ind;
if (vcline >= vcnt)
dot -= vcline - vcnt + 1, vcline = vcnt - 1;
getDOT();
}
}
 
/*
* Like vup, but scrolling down.
*/
void
vdown(register int cnt, register int ind, int scroll)
{
register int i, tot;
 
if (dot == dol) {
beep();
return;
}
vsave();
i = dol - dot;
if (cnt > i) {
ind -= cnt - i;
if (ind < 0)
ind = 0;
cnt = i;
}
i = vcnt - vcline - 1;
if (!scroll && cnt <= i) {
vshow(dot + cnt, NOLINE);
return;
}
cnt -= i, dot += i, vcline += i;
if (hold & HOLDWIG)
goto dcontxt;
if (!scroll) {
tot = WECHO - ZERO;
if (state != VISUAL || cnt - tot > 0 || vfit(dot, cnt) > tot / 3 + 1) {
dcontxt:
vcontext(dot + cnt, '.');
return;
}
}
if (cnt > 0)
vroll(cnt);
if (state == VISUAL && scroll) {
vcline -= ind, dot -= ind;
if (vcline < 0)
dot -= vcline, vcline = 0;
getDOT();
}
}
 
/*
* Show line addr in context where on the screen.
* Work here is in determining new top line implied by
* this placement of line addr, since we always draw from the top.
*/
void
vcontext(register line *addr, int where)
{
register line *top;
 
getline(*addr);
if (state != VISUAL)
top = addr;
else switch (where) {
 
case '^':
addr = vback(addr, basWLINES - vdepth());
getline(*addr);
/* fall into ... */
 
case '-':
top = vback(addr, basWLINES - vdepth());
getline(*addr);
break;
 
case '.':
top = vback(addr, basWLINES / 2 - vdepth());
getline(*addr);
break;
 
default:
top = addr;
break;
}
if (state == ONEOPEN && LINE(0) == WBOT)
vup1();
vcnt = vcline = 0;
vclean();
if (state == CRTOPEN)
vup1();
vshow(addr, top);
}
 
/*
* Get a clean line. If we are in a hard open
* we may be able to reuse the line we are on
* if it is blank. This is a real win.
*/
void
vclean(void)
{
 
if (state != VISUAL && state != CRTOPEN) {
destcol = 0;
if (!ateopr())
vup1();
vcnt = 0;
}
}
 
/*
* Show line addr with the specified top line on the screen.
* Top may be 0; in this case have vcontext compute the top
* (and call us recursively). Eventually, we clear the screen
* (or its open mode equivalent) and redraw.
*/
void
vshow(line *addr, line *top)
{
register int cnt = addr - dot;
register int i = vcline + cnt;
short oldhold = hold;
 
if (state != HARDOPEN && state != ONEOPEN && i >= 0 && i < vcnt) {
dot = addr;
getDOT();
vcline = i;
return;
}
if (state != VISUAL) {
dot = addr;
vopen(dot, WBOT);
return;
}
if (top == 0) {
vcontext(addr, '.');
return;
}
dot = top;
oldhold = hold;
hold |= HOLDAT;
vclear();
vreset(0);
vredraw(WTOP);
/* error if vcline >= vcnt ! */
vcline = addr - top;
dot = addr;
getDOT();
hold = oldhold;
vsync(LASTLINE);
}
 
/*
* reset the state.
* If inecho then leave us at the beginning of the echo
* area; we are called this way in the middle of a :e escape
* from visual, e.g.
*/
void
vreset(int inecho)
{
 
vcnt = vcline = 0;
WTOP = basWTOP;
WLINES = basWLINES;
if (inecho)
splitw = 1, vgoto(WECHO, 0);
}
 
/*
* Starting from which line preceding tp uses almost (but not more
* than) cnt physical lines?
*/
line *
vback(register line *tp, register int cnt)
{
register int d;
 
if (cnt > 0)
for (; tp > one; tp--) {
getline(tp[-1]);
d = vdepth();
if (d > cnt)
break;
cnt -= d;
}
return (tp);
}
 
/*
* How much scrolling will it take to roll cnt lines starting at tp?
*/
int
vfit(register line *tp, int cnt)
{
register int j;
 
j = 0;
while (cnt > 0) {
cnt--;
getline(tp[cnt]);
j += vdepth();
}
if (tp > dot)
j -= WBOT - LASTLINE;
return (j);
}
 
/*
* Roll cnt lines onto the screen.
*/
void
vroll(register int cnt)
{
short oldhold = hold;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vroll(%d)\n", cnt);
#endif
if (state != VISUAL)
hold |= HOLDAT|HOLDROL;
if (WBOT == WECHO) {
vcnt = 0;
if (state == ONEOPEN)
vup1();
}
for (; cnt > 0 && Peekkey != ATTN; cnt--) {
dot++, vcline++;
vopen(dot, LASTLINE);
vscrap();
}
hold = oldhold;
if (state == HARDOPEN)
sethard();
vsyncCL();
}
 
/*
* Roll backwards (scroll up).
*/
void
vrollR(register int cnt)
{
short oldhold = hold;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vrollR(%d), dot=%d\n", cnt, lineDOT());
#endif
if (WBOT == WECHO)
vcnt = 0;
heldech = 0;
hold |= HOLDAT|HOLDECH;
for (; cnt > 0 && Peekkey != ATTN; cnt--) {
dot--;
vopen(dot, WTOP);
vscrap();
}
hold = oldhold;
if (heldech)
vclrech(0);
vsync(LINE(vcnt-1));
}
 
/*
* Go into cooked mode (allow interrupts) during
* a scroll if we are at less than 1200 baud and not
* a 'vi' command, of if we are in a 'vi' command and the
* scroll is more than 2 full screens.
*
* BUG: An interrupt during a scroll in this way
* dumps to command mode.
*/
int
vcookit(register int cnt)
{
 
return (cnt > 1 && (ospeed < B1200 && !initev || cnt > TLINES * 2));
}
 
/*
* Determine displayed depth of current line.
*/
int
vdepth(void)
{
register int d;
 
d = (column(NOSTR) + WCOLS - 1 + (Putchar == listchar) + IN) / WCOLS;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vdepth returns %d\n", d == 0 ? 1 : d);
#endif
return (d == 0 ? 1 : d);
}
 
/*
* Move onto a new line, with cursor at position curs.
*/
void
vnline(char *curs)
{
 
if (curs)
wcursor = curs;
else if (vmoving)
wcursor = vfindcol(vmovcol);
else
wcursor = vskipwh(linebuf);
cursor = linebuf;
vmove(0);
}
/ports/trunk/editors/exvi/libterm/Makefile
0,0 → 1,64
#
# 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.
#
# from Makefile 5.1 (Berkeley) 6/5/85
#
# Sccsid @(#)Makefile 1.2 (gritter) 2/4/02
#
DEFS = -DCM_N -DCM_GT -DCM_B -DCM_D
# COPT comes from ex.
CFLAGS = $(DEFS) $(COPT)
SRCS = termcap.c tgoto.c tputs.c
OBJS = termcap.o tgoto.o tputs.o
 
.c.o: ; $(CC) $(CFLAGS) -c $<
 
all: libtermlib.a
 
libtermlib.a: $(OBJS)
ar cr libtermlib.a $(OBJS)
 
clean:
rm -f libtermlib.a $(OBJS) core
 
# DO NOT DELETE
 
termcap.o: libterm.h
tgoto.o: libterm.h
tputs.o: libterm.h
/ports/trunk/editors/exvi/ex_vadj.c
0,0 → 1,1162
/*
* 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_vadj.c 1.11 (gritter) 3/4/05";
#endif
#endif
 
/* from ex_vadj.c 7.9 (Berkeley) 6/7/85 */
 
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
 
/*
* Routines to deal with management of logical versus physical
* display, opening and redisplaying lines on the screen, and
* use of intelligent terminal operations. Routines to deal with
* screen cleanup after a change.
*/
 
/*
* Display a new line at physical line p, returning
* the depth of the newly displayed line. We may decide
* to expand the window on an intelligent terminal if it is
* less than a full screen by deleting a line above the top of the
* window before doing an insert line to keep all the good text
* on the screen in which case the line may actually end up
* somewhere other than line p.
*/
void
vopen(line *tp, int p)
{
register int cnt;
register struct vlinfo *vp, *vpc;
 
#ifdef ADEBUG
if (trace != NULL)
tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p);
#endif
if (state != VISUAL) {
if (vcnt)
if (hold & HOLDROL)
vup1();
else
vclean();
 
/*
* Forget all that we once knew.
*/
vcnt = vcline = 0;
p = WBOT; LASTLINE = WBOT + 1;
state = bastate;
WTOP = basWTOP;
WLINES = basWLINES;
}
vpc = &vlinfo[vcline];
for (vp = &vlinfo[vcnt]; vp >= vpc; vp--)
vlcopy(vp[1], vp[0]);
vcnt++;
if (Pline == numbline)
/*
* Dirtying all the lines is rather inefficient
* internally, but number mode is used rarely
* and so its not worth optimizing.
*/
vdirty(vcline+1, WECHO);
getline(*tp);
 
/*
* If we are opening at the top of the window, can try a window
* expansion at the top.
*/
if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ZERO) {
cnt = p + vdepth() - LINE(1);
if (cnt > 0) {
p -= cnt;
if (p < ZERO)
p = ZERO;
WTOP = p;
WLINES = WBOT - WTOP + 1;
}
}
vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0;
cnt = vreopen(p, lineno(tp), vcline);
if (vcline + 1 == vcnt)
LINE(vcnt) = LINE(vcline) + cnt;
}
 
/*
* Redisplay logical line l at physical line p with line number lineno.
*/
int
vreopen(int p, int lineno, int l)
{
register int d;
register struct vlinfo *vp = &vlinfo[l];
 
if (p < 0)
error("Line too long to fit on screen");
d = vp->vdepth;
if (d == 0 || (vp->vflags & VDIRT))
vp->vdepth = d = vdepth();
vp->vliny = p, vp->vflags &= ~VDIRT;
 
/*
* Try to win by making the screen larger rather than inserting
* a line and driving text off the bottom.
*/
p = vglitchup(l, 0);
 
/*
* BUG: Should consider using CE here to clear to end of line.
* As it stands we always strike over the current text.
* Since often the current text is the same as what
* we are overstriking with, it tends not to show.
* On the other hand if it is different and we end up
* spacing out a lot of text, we could have won with
* a CE. This is probably worthwhile at low speed
* only however, since clearly computation will be
* necessary to determine which way to go.
*/
vigoto(p, 0);
pline(lineno);
 
/*
* When we are typing part of a line for hardcopy open, don't
* want to type the '$' marking an end of line if in list mode.
*/
if (hold & HOLDDOL)
return (d);
if (Putchar == listchar)
putchar('$');
 
/*
* Optimization of cursor motion may prevent screen rollup if the
* line has blanks/tabs at the end unless we force the cursor to appear
* on the last line segment.
*/
if (vp->vliny + d - 1 > WBOT)
vcsync();
 
/*
* Switch into hardcopy open mode if we are in one line (adm3)
* open mode and this line is now too long. If in hardcopy
* open mode, then call sethard to move onto the next line
* with appropriate positioning.
*/
if (state == ONEOPEN) {
WCOLS = OCOLUMNS;
if (vdepth() > 1) {
WCOLS = TUBECOLS;
sethard();
} else
WCOLS = TUBECOLS;
} else if (state == HARDOPEN)
sethard();
 
/*
* Unless we filled (completely) the last line we typed on,
* we have to clear to the end of the line
* in case stuff is left from before.
*/
if (vp->vliny + d > destline) {
if (IN && destcol == WCOLS)
vigoto(vp->vliny + d - 1, 0);
vclreol();
}
return (d);
}
 
/*
* Real work for winning growing of window at top
* when inserting in the middle of a partially full
* screen on an intelligent terminal. We have as argument
* the logical line number to be inserted after, and the offset
* from that line where the insert will go.
* We look at the picture of depths and positions, and if we can
* delete some (blank) lines from the top of the screen so that
* later inserts will not push stuff off the bottom.
*/
int
vglitchup(int l, int o)
{
register struct vlinfo *vp = &vlinfo[l];
register int need;
register int p = vp->vliny;
short oldhold = 0, oldheldech = 0;
bool glitched = 0;
 
if (l < vcnt - 1) {
need = p + vp->vdepth - (vp+1)->vliny;
if (need > 0) {
if (state == VISUAL && WTOP - ZERO >= need && AL && DL) {
glitched++;
WTOP -= need;
WLINES = WBOT - WTOP + 1;
p -= need;
if (p + o == WTOP) {
vp->vliny = WTOP;
return (WTOP + o);
}
vdellin(WTOP, need, -1);
oldheldech = heldech;
oldhold = hold;
hold |= HOLDECH;
}
vinslin((vp+1)->vliny, need, l);
if (glitched) {
hold = oldhold;
heldech = oldheldech;
}
}
} else
vp[1].vliny = vp[0].vliny + vp->vdepth;
return (p + o);
}
 
/*
* Insert cnt blank lines before line p,
* logically and (if supported) physically.
*/
void
vinslin(register int p, register int cnt, int l)
{
register int i;
bool could = 1;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l);
#endif
if (p + cnt > WBOT && CD) {
/*
* Really quick -- clear to end of screen.
*/
cnt = WECHO + 1 - p;
vgoto(p, 0), vputp(CD, cnt);
vclrech(1);
vadjAL(p, cnt);
} else if (SR && p == WTOP && costSR < costAL) {
/*
* Use reverse scroll mode of the terminal, at
* the top of the window. Reverse linefeed works
* too, since we only use it from line WTOP.
*/
for (i = cnt; i > 0; i--) {
vgoto(p, 0), vputp(SR, 0);
if (i > 1 && (hold & HOLDAT) == 0)
putchar('@');
/*
* If we are at the top of the screen, and the
* terminal retains display above, then we
* should try to clear to end of line.
* Have to use CE since we don't remember what is
* actually on the line.
*/
if (CE && (DA || p != 0))
vputp(CE, 1);
}
vadjAL(p, cnt);
} else if (AL) {
/*
* Use insert line.
*/
vgoto(p, 0);
if (AL_PARM && (cnt>1 || *AL==0)) {
/* insert cnt lines. Should do @'s too. */
vputp(tgoto(AL_PARM, p, cnt), WECHO+1-p);
}
else if (xCS && *AL==0) {
/* vt100 change scrolling region to fake AL */
vputp(SC, 1);
vputp(tgoto(xCS, TLINES-1,p), 1);
vputp(RC, 1); /* xCS homes stupid cursor */
for (i=cnt; i>0; i--)
vputp(SR, 1); /* should do @'s */
vputp(tgoto(xCS, TLINES-1,0), 1);
vputp(RC, 1); /* Once again put it back */
}
else {
vputp(AL, WECHO + 1 - p);
for (i = cnt - 1; i > 0; i--) {
vgoto(outline+1, 0);
vputp(AL, WECHO + 1 - outline);
if ((hold & HOLDAT) == 0)
putchar('@');
}
}
vadjAL(p, cnt);
} else
could = 0;
vopenup(cnt, could, l);
}
 
/*
* Logically open up after line l, cnt of them.
* We need to know if it was done ``physically'' since in this
* case we accept what the hardware gives us. If we have to do
* it ourselves (brute force) we will squish out @ lines in the process
* if this will save us work.
*/
void
vopenup(int cnt, int could, int l)
{
register struct vlinfo *vc = &vlinfo[l + 1];
register struct vlinfo *ve = &vlinfo[vcnt];
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l);
#endif
if (could)
/*
* This will push @ lines down the screen,
* just as the hardware did. Since the default
* for intelligent terminals is to never have @
* lines on the screen, this should never happen,
* and the code makes no special effort to be nice in this
* case, e.g. squishing out the @ lines by delete lines
* before doing append lines.
*/
for (; vc <= ve; vc++)
vc->vliny += cnt;
else {
/*
* Will have to clean up brute force eventually,
* so push the line data around as little as possible.
*/
vc->vliny += cnt, vc->vflags |= VDIRT;
while (vc < ve) {
register int i = vc->vliny + vc->vdepth;
 
vc++;
if (i <= vc->vliny)
break;
vc->vliny = i, vc->vflags |= VDIRT;
}
}
vscrap();
}
 
/*
* Adjust data structure internally to account for insertion of
* blank lines on the screen.
*/
void
vadjAL(int p, int cnt)
{
cell *tlines[TUBELINES];
register int from, to;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt);
#endif
copy(tlines, vtube, sizeof vtube); /*SASSIGN*/
for (from = p, to = p + cnt; to <= WECHO; from++, to++)
vtube[to] = tlines[from];
for (to = p; from <= WECHO; from++, to++) {
vtube[to] = tlines[from];
vclrcell(vtube[to], WCOLS);
}
/*
* Have to clear the echo area since its contents aren't
* necessarily consistent with the rest of the display.
*/
vclrech(0);
}
 
/*
* Roll the screen up logically and physically
* so that line dl is the bottom line on the screen.
*/
void
vrollup(int dl)
{
register int cnt;
register int dc = destcol;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vrollup(%d)\n", dl);
#endif
cnt = dl - (splitw ? WECHO : WBOT);
if (splitw && (state == VISUAL || state == CRTOPEN))
holdupd = 1;
vmoveitup(cnt, 1);
vscroll(cnt);
destline = dl - cnt, destcol = dc;
}
 
void
vup1(void)
{
 
vrollup(WBOT + 1);
}
 
/*
* Scroll the screen up cnt lines physically.
* If doclr is true, do a clear eol if the terminal
* has standout (to prevent it from scrolling up)
*/
void
vmoveitup(register int cnt, int doclr)
{
 
if (cnt == 0)
return;
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt);
#endif
if (doclr && (SO || SE))
vclrech(0);
if (SF) {
destline = WECHO;
destcol = (NONL ? 0 : outcol % WCOLS);
fgoto();
while (cnt > 0)
vputp(SF, 0), cnt--;
return;
}
destline = WECHO + cnt;
destcol = (NONL ? 0 : outcol % WCOLS);
fgoto();
if (state == ONEOPEN || state == HARDOPEN) {
outline = destline = 0;
vclrcell(vtube[0], WCOLS);
}
}
 
/*
* Scroll the screen up cnt lines logically.
*/
void
vscroll(register int cnt)
{
register int from, to;
cell *tlines[TUBELINES];
 
#ifdef ADEBUG
if (trace)
fprintf(trace, "vscroll(%d)\n", cnt);
#endif
if (cnt < 0 || cnt > TUBELINES)
error(catgets(catd, 1, 219, "Internal error: vscroll"));
if (cnt == 0)
return;
copy(tlines, vtube, sizeof vtube);
for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++)
vtube[to] = tlines[from];
for (from = ZERO; to <= WECHO; to++, from++) {
vtube[to] = tlines[from];
vclrcell(vtube[to], WCOLS);
}
for (from = 0; from <= vcnt; from++)
LINE(from) -= cnt;
}
 
/*
* Discard logical lines due to physical wandering off the screen.
*/
void
vscrap(void)
{
register int i, j;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vscrap\n"), tvliny();
#endif
if (splitw)
return;
if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) {
WTOP = LINE(0);
WLINES = WBOT - WTOP + 1;
}
for (j = 0; j < vcnt; j++)
if (LINE(j) >= WTOP) {
if (j == 0)
break;
/*
* Discard the first j physical lines off the top.
*/
vcnt -= j, vcline -= j;
for (i = 0; i <= vcnt; i++)
vlcopy(vlinfo[i], vlinfo[i + j]);
break;
}
/*
* Discard lines off the bottom.
*/
if (vcnt) {
for (j = 0; j <= vcnt; j++)
if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) {
vcnt = j;
break;
}
LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1);
}
#ifdef ADEBUG
if (trace)
tvliny();
#endif
/*
* May have no lines!
*/
}
 
/*
* Repaint the screen, with cursor at curs, aftern an arbitrary change.
* Handle notification on large changes.
*/
void
vrepaint(char *curs)
{
 
wdot = NOLINE;
/*
* In open want to notify first.
*/
noteit(0);
vscrap();
 
/*
* Deal with a totally useless display.
*/
if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) {
register line *odol = dol;
 
vcnt = 0;
if (holdupd)
if (state == VISUAL)
ignore(peekkey());
else
vup1();
holdupd = 0;
if (odol == zero)
fixzero();
vcontext(dot, '.');
noteit(1);
if (noteit(1) == 0 && odol == zero) {
CATCH
error(catgets(catd, 1, 220,
"No lines in buffer"));
ENDCATCH
linebuf[0] = 0;
splitw = 0;
}
vnline(curs);
return;
}
 
/*
* Have some useful displayed text; refresh it.
*/
getDOT();
 
/*
* This is for boundary conditions in open mode.
*/
if (FLAGS(0) & VDIRT)
vsync(WTOP);
/*
* If the current line is after the last displayed line
* or the bottom of the screen, then special effort is needed
* to get it on the screen. We first try a redraw at the
* last line on the screen, hoping it will fill in where @
* lines are now. If this doesn't work, then roll it onto
* the screen.
*/
if (vcline >= vcnt || LINE(vcline) > WBOT) {
short oldhold = hold;
hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold;
if (vcline >= vcnt) {
register int i = vcline - vcnt + 1;
 
dot -= i;
vcline -= i;
vroll(i);
} else
vsyncCL();
} else
vsync(vcline > 0 ? LINE(vcline - 1) : WTOP);
 
/*
* Notification on large change for visual
* has to be done last or we may lose
* the echo area with redisplay.
*/
noteit(1);
 
/*
* Finally. Move the cursor onto the current line.
*/
vnline(curs);
}
 
/*
* Fully cleanup the screen, leaving no @ lines except at end when
* line after last won't completely fit. The routine vsync is
* more conservative and much less work on dumb terminals.
*/
void
vredraw(register int p)
{
register int l;
register line *tp;
char temp[LBSIZE];
bool anydl = 0;
short oldhold = hold;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny();
#endif
if (holdupd) {
holdupd = 3;
return;
}
if (state == HARDOPEN || splitw)
return;
if (p < 0 /* || p > WECHO */)
error(catgets(catd, 1, 221, "Internal error: vredraw"));
 
/*
* Trim the ragged edges (lines which are off the screen but
* not yet logically discarded), save the current line, and
* search for first logical line affected by the redraw.
*/
vscrap();
CP(temp, linebuf);
l = 0;
tp = dot - vcline;
if (vcnt == 0)
LINE(0) = WTOP;
while (l < vcnt && LINE(l) < p)
l++, tp++;
 
/*
* We hold off echo area clearing during the redraw in deference
* to a final clear of the echo area at the end if appropriate.
*/
heldech = 0;
hold |= HOLDECH;
for (; l < vcnt && Peekkey != ATTN; l++) {
if (l == vcline)
strcLIN(temp);
else
getline(*tp);
 
/*
* Delete junk between displayed lines.
*/
if (LINE(l) != LINE(l + 1) && LINE(l) != p) {
if (anydl == 0 && DB && CD) {
hold = oldhold;
vclrech(0);
anydl = 1;
hold |= HOLDECH;
heldech = 0;
}
vdellin(p, LINE(l) - p, l);
}
 
/*
* If line image is not know to be up to date, then
* redisplay it; else just skip onward.
*/
LINE(l) = p;
if (FLAGS(l) & VDIRT) {
DEPTH(l) = vdepth();
if (l != vcline && p + DEPTH(l) - 1 > WBOT) {
vscrap();
break;
}
FLAGS(l) &= ~VDIRT;
vreopen(p, lineno(tp), l);
p = LINE(l) + DEPTH(l);
} else
p += DEPTH(l);
tp++;
}
 
/*
* That takes care of lines which were already partially displayed.
* Now try to fill the rest of the screen with text.
*/
if (state == VISUAL && p <= WBOT) {
int ovcline = vcline;
 
vcline = l;
for (; tp <= dol && Peekkey != ATTN; tp++) {
getline(*tp);
if (p + vdepth() - 1 > WBOT)
break;
vopen(tp, p);
p += DEPTH(vcline);
vcline++;
}
vcline = ovcline;
}
 
/*
* Thats all the text we can get on.
* Now rest of lines (if any) get either a ~ if they
* are past end of file, or an @ if the next line won't fit.
*/
for (; p <= WBOT && Peekkey != ATTN; p++)
vclrlin(p, tp);
strcLIN(temp);
hold = oldhold;
if (heldech)
vclrech(0);
#ifdef ADEBUG
if (trace)
tvliny();
#endif
}
 
/*
* Do the real work in deleting cnt lines starting at line p from
* the display. First affected line is line l.
*/
void
vdellin(int p, int cnt, int l)
{
register int i;
 
if (cnt == 0)
return;
if (DL == NOSTR || cnt < 0) {
/*
* Can't do it; just remember that line l is munged.
*/
FLAGS(l) |= VDIRT;
return;
}
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l);
#endif
/*
* Send the deletes to the screen and then adjust logical
* and physical internal data structures.
*/
vgoto(p, 0);
if (DL_PARM && (cnt>1 || *DL==0)) {
vputp(tgoto(DL_PARM, p, cnt), WECHO-p);
}
else if (xCS && *DL==0) {
/* vt100: fake DL by changing scrolling region */
vputp(SC, 1); /* Save since xCS homes stupid cursor */
vputp(tgoto(xCS, TLINES-1, p), 1);
vputp(tgoto(CM, 0, TLINES-1), 1);/* Go to lower left corner */
for (i=0; i<cnt; i++) /* .. and scroll cnt times */
putch('\n'); /* should check NL too */
vputp(tgoto(xCS, TLINES-1, 0), 1);/* restore scrolling region */
vputp(RC, 1); /* put cursor back */
}
else {
for (i = 0; i < cnt; i++)
vputp(DL, WECHO - p);
}
vadjDL(p, cnt);
vcloseup(l, cnt);
}
/*
* Adjust internal physical screen image to account for deleted lines.
*/
void
vadjDL(int p, int cnt)
{
cell *tlines[TUBELINES];
register int from, to;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt);
#endif
/*
* Would like to use structured assignment but early
* v7 compiler (released with phototypesetter for v6)
* can't hack it.
*/
copy(tlines, vtube, sizeof vtube); /*SASSIGN*/
for (from = p + cnt, to = p; from <= WECHO; from++, to++)
vtube[to] = tlines[from];
for (from = p; to <= WECHO; from++, to++) {
vtube[to] = tlines[from];
vclrcell(vtube[to], WCOLS);
}
}
/*
* Sync the screen, like redraw but more lazy and willing to leave
* @ lines on the screen. VsyncCL syncs starting at the current line.
* In any case, if the redraw option is set then all syncs map to redraws
* as if vsync didn't exist.
*/
void
vsyncCL(void)
{
 
vsync(LINE(vcline));
}
 
void
vsync(register int p)
{
 
if (value(REDRAW))
vredraw(p);
else
vsync1(p);
}
 
/*
* The guts of a sync. Similar to redraw but
* just less ambitous.
*/
void
vsync1(register int p)
{
register int l;
char temp[LBSIZE];
register struct vlinfo *vp = &vlinfo[0];
short oldhold = hold;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny();
#endif
if (holdupd) {
if (holdupd < 3)
holdupd = 2;
return;
}
if (state == HARDOPEN || splitw)
return;
vscrap();
CP(temp, linebuf);
if (vcnt == 0)
LINE(0) = WTOP;
l = 0;
while (l < vcnt && vp->vliny < p)
l++, vp++;
heldech = 0;
hold |= HOLDECH;
while (p <= WBOT && Peekkey != ATTN) {
/*
* Want to put a line here if not in visual and first line
* or if there are lies left and this line starts before
* the current line, or if this line is piled under the
* next line (vreplace does this and we undo it).
*/
if (l == 0 && state != VISUAL ||
(l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) {
if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) {
if (l == vcline)
strcLIN(temp);
else
getline(dot[l - vcline]);
/*
* Be careful that a long line doesn't cause the
* screen to shoot up.
*/
if (l != vcline && (vp->vflags & VDIRT)) {
vp->vdepth = vdepth();
vp->vflags &= ~VDIRT;
if (p + vp->vdepth - 1 > WBOT)
break;
}
vreopen(p, lineDOT() + (l - vcline), l);
}
p = vp->vliny + vp->vdepth;
vp++;
l++;
} else
/*
* A physical line between logical lines,
* so we settle for an @ at the beginning.
*/
vclrlin(p, dot + (l - vcline)), p++;
}
strcLIN(temp);
hold = oldhold;
if (heldech)
vclrech(0);
}
 
/*
* Subtract (logically) cnt physical lines from the
* displayed position of lines starting with line l.
*/
void
vcloseup(int l, register int cnt)
{
register int i;
 
#ifdef ADEBUG
if (trace)
tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt);
#endif
for (i = l + 1; i <= vcnt; i++)
LINE(i) -= cnt;
}
 
/*
* Workhorse for rearranging line descriptors on changes.
* The idea here is that, starting with line l, cnt lines
* have been replaced with newcnt lines. All of these may
* be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0,
* since we may be called from an undo after the screen has
* moved a lot. Thus we have to be careful.
*
* Many boundary conditions here.
*/
void
vreplace(int l, int cnt, int newcnt)
{
register int from, to, i;
bool savenote = 0;
 
#ifdef ADEBUG
if (trace) {
tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt);
tvliny();
}
#endif
if (l >= vcnt)
return;
if (l < 0) {
if (l + cnt < 0) {
/*
* Nothing on the screen is relevant.
* Settle for redrawing from scratch (later).
*/
vcnt = 0;
return;
}
/*
* Normalize l to top of screen; the add is
* really a subtract from cnt since l is negative.
*/
cnt += l;
l = 0;
 
/*
* Unseen lines were affect so notify (later).
*/
savenote++;
}
 
/*
* These shouldn't happen
* but would cause great havoc.
*/
if (cnt < 0)
cnt = 0;
if (newcnt < 0)
newcnt = 0;
 
/*
* Surely worthy of note if more than report
* lines were changed.
*/
if (cnt > value(REPORT) || newcnt > value(REPORT))
savenote++;
 
/*
* Same number of lines affeted as on screen, and we
* can insert and delete lines. Thus we just type
* over them, since otherwise we will push them
* slowly off the screen, a clear lose.
*/
if (cnt == newcnt || vcnt - l == newcnt && AL && DL) {
if (cnt > 1 && l + cnt > vcnt)
savenote++;
vdirty(l, newcnt);
} else {
/*
* Lines are going away, squish them out.
*/
if (cnt > 0) {
/*
* If non-displayed lines went away,
* always notify.
*/
if (cnt > 1 && l + cnt > vcnt)
savenote++;
if (l + cnt >= vcnt)
cnt = vcnt - l;
else
for (from = l + cnt, to = l; from <= vcnt; to++, from++)
vlcopy(vlinfo[to], vlinfo[from]);
vcnt -= cnt;
}
/*
* Open up space for new lines appearing.
* All new lines are piled in the same place,
* and will be unpiled by vredraw/vsync, which
* inserts lines in front as it unpiles.
*/
if (newcnt > 0) {
/*
* Newlines are appearing which may not show,
* so notify (this is only approximately correct
* when long lines are present).
*/
if (newcnt > 1 && l + newcnt > vcnt + 1)
savenote++;
 
/*
* If there will be more lines than fit, then
* just throw way the rest of the stuff on the screen.
*/
if (l + newcnt > WBOT && AL && DL) {
vcnt = l;
goto skip;
}
from = vcnt, to = vcnt + newcnt;
i = TUBELINES - to;
if (i < 0)
from += i, to += i;
vcnt = to;
for (; from >= l; from--, to--)
vlcopy(vlinfo[to], vlinfo[from]);
for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) {
LINE(to) = LINE(from);
DEPTH(to) = 0;
FLAGS(to) = VDIRT;
}
}
}
skip:
if (Pline == numbline && cnt != newcnt)
/*
* When lines positions are shifted, the numbers
* will be wrong.
*/
vdirty(l, WECHO);
if (!savenote)
notecnt = 0;
#ifdef ADEBUG
if (trace)
tvliny();
#endif
}
 
/*
* Start harcopy open.
* Print an image of the line to the left of the cursor
* under the full print of the line and position the cursor.
* If we are in a scroll ^D within hardcopy open then all this
* is suppressed.
*/
void
sethard(void)
{
 
if (state == VISUAL)
return;
rubble = 0;
state = HARDOPEN;
if (hold & HOLDROL)
return;
vup1();
LINE(0) = WBOT;
if (Pline == numbline)
vgoto(WBOT, 0), printf("%6d ", lineDOT());
}
 
/*
* Mark the lines starting at base for i lines
* as dirty so that they will be checked for correct
* display at next sync/redraw.
*/
void
vdirty(register int base, register int i)
{
register int l;
for (l = base; l < vcnt; l++) {
if (--i < 0)
return;
FLAGS(l) |= VDIRT;
}
}
/ports/trunk/editors/exvi/ex_vget.c
0,0 → 1,879
/*
* 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_vget.c 1.29 (gritter) 2/15/05";
#endif
#endif
 
/* from ex_vget.c 6.8.1 (2.11BSD GTE) 12/9/94 */
 
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
 
/*
* Input routines for open/visual.
* We handle reading from the echo area here as well as notification on
* large changes which appears in the echo area.
*/
 
/*
* Return the key.
*/
void
ungetkey (
int c /* mjm: char --> int */
)
{
 
if (Peekkey != ATTN)
Peekkey = c;
}
 
/*
* Return a keystroke, but never a ^@.
*/
int
getkey(void)
{
register int c; /* mjm: char --> int */
 
do {
c = getbr();
if (c==0)
beep();
} while (c == 0);
return (c);
}
 
/*
* Tell whether next keystroke would be a ^@.
*/
int
peekbr(void)
{
 
Peekkey = getbr();
return (Peekkey == 0);
}
 
short precbksl;
JMP_BUF readbuf;
int doingread = 0;
 
static int
readwc(int fd, int *cp)
{
int c;
char b;
 
#ifdef MB
if (mb_cur_max > 1) {
static char pbuf[2][MB_LEN_MAX], *pend[2], *pcur[2];
static mbstate_t state[2];
static int incompl[2];
int i, rest;
int idx = fd ? 1 : 0;
wchar_t wc;
size_t sz;
 
i = 0;
rest = pend[idx] - pcur[idx];
if (rest && pcur[idx] > pbuf[idx]) {
do
pbuf[idx][i] = pcur[idx][i];
while (i++, --rest);
} else if (incompl[idx]) {
pend[idx] = pcur[idx] = NULL;
return -1;
}
if (i == 0) {
if ((c = read(fd, &b, 1)) <= 0) {
pend[idx] = pcur[idx] = NULL;
return c;
}
pbuf[idx][i++] = b;
}
if (pbuf[idx][0] & 0200) {
sz = 1;
while ((sz = mbrtowc(&wc, pbuf[idx], i, &state[idx]))
== (size_t)-2 && i < mb_cur_max) {
if ((c = read(fd, &b, 1)) <= 0) {
incompl[idx] = 1;
break;
} else
pbuf[idx][i++] = b;
memset(&state[idx], 0, sizeof state[idx]);
}
if (sz == (size_t)-2 || sz == (size_t)-1 ||
!widthok(wc)) {
memset(&state[idx], 0, sizeof state[idx]);
c = 1;
*cp = pbuf[idx][0] | INVBIT;
} else if (sz == 0) {
c = 1;
*cp = wc;
} else {
c = sz;
*cp = wc;
}
} else {
c = 1;
*cp = pbuf[idx][0];
}
pcur[idx] = &pbuf[idx][c];
pend[idx] = &pcur[idx][i-c];
return c;
} else
#endif /* MB */
{
c = read(fd, &b, 1);
*cp = b;
return c;
}
}
 
/*
* Get a keystroke, including a ^@.
* If an key was returned with ungetkey, that
* comes back first. Next comes unread input (e.g.
* from repeating commands with .), and finally new
* keystrokes.
*/
int
getbr(void)
{
int ch;
register int c;
#ifdef UCVISUAL
register int d;
register char *colp;
#endif
#ifdef BEEHIVE
int cnt;
static char Peek2key;
#endif
extern short slevel, ttyindes;
 
getATTN:
if (Peekkey) {
c = Peekkey;
Peekkey = 0;
return (c);
}
#ifdef BEEHIVE
if (Peek2key) {
c = Peek2key;
Peek2key = 0;
return (c);
}
#endif
if (vglobp) {
if (*vglobp)
return (lastvgk = *vglobp++);
lastvgk = 0;
return (ESCAPE);
}
if (vmacp) {
if (*vmacp) {
int n;
nextc(ch, vmacp, n);
vmacp += n;
return (ch);
}
/* End of a macro or set of nested macros */
vmacp = 0;
if (inopen == -1) /* don't screw up undo for esc esc */
vundkind = VMANY;
inopen = 1; /* restore old setting now that macro done */
vch_mac = VC_NOTINMAC;
}
flusho();
for (c =0; abbrevs[c].mapto; c++)
abbrevs[c].hadthis = 0;
#ifdef UCVISUAL
again:
#endif
if (SETJMP(readbuf))
goto getATTN;
doingread = 1;
c = readwc(slevel == 0 ? 0 : ttyindes, &ch);
doingread = 0;
if (c < 1) {
if (errno == EINTR)
goto getATTN;
error(catgets(catd, 1, 222, "Input read error"));
}
c = ch & TRIM;
#ifdef BEEHIVE
if (XB && slevel==0 && c == ESCAPE) {
if (readwc(0, &Peek2key) < 1)
goto getATTN;
Peek2key &= TRIM;
switch (Peek2key) {
case 'C': /* SPOW mode sometimes sends \EC for space */
c = ' ';
Peek2key = 0;
break;
case 'q': /* f2 -> ^C */
c = CTRL('c');
Peek2key = 0;
break;
case 'p': /* f1 -> esc */
Peek2key = 0;
break;
}
}
#endif
 
#ifdef UCVISUAL
/*
* The algorithm here is that of the UNIX kernel.
* See the description in the programmers manual.
*/
if (UPPERCASE) {
if (xisupper(c))
c = xtolower(c);
if (c == '\\') {
if (precbksl < 2)
precbksl++;
if (precbksl == 1)
goto again;
} else if (precbksl) {
d = 0;
if (xislower(c))
d = xtoupper(c);
else {
colp = "({)}!|^~'~";
while (d = *colp++)
if (d == c) {
d = *colp++;
break;
} else
colp++;
}
if (precbksl == 2) {
if (!d) {
Peekkey = c;
precbksl = 0;
c = '\\';
}
} else if (d)
c = d;
else {
Peekkey = c;
precbksl = 0;
c = '\\';
}
}
if (c != '\\')
precbksl = 0;
}
#endif
 
#ifdef TRACE
if (trace) {
if (!techoin) {
tfixnl();
techoin = 1;
fprintf(trace, "*** Input: ");
}
tracec(c);
}
#endif
lastvgk = 0;
return (c);
}
 
/*
* Get a key, but if a delete, quit or attention
* is typed return 0 so we will abort a partial command.
*/
int
getesc(void)
{
register int c;
 
c = getkey();
if (c == ATTN)
goto case_ATTN;
switch (c) {
 
case CTRL('v'):
case CTRL('q'):
c = getkey();
return (c);
 
case QUIT:
case_ATTN:
ungetkey(c);
return (0);
 
case ESCAPE:
return (0);
}
return (c);
}
 
/*
* Peek at the next keystroke.
*/
int
peekkey(void)
{
 
Peekkey = getkey();
return (Peekkey);
}
 
/*
* Read a line from the echo area, with single character prompt c.
* A return value of 1 means the user blewit or blewit away.
*/
int
readecho(int c)
{
register char *sc = cursor;
register void (*OP)(int);
bool waste;
register int OPeek;
 
if (WBOT == WECHO)
vclean();
else
vclrech(0);
splitw++;
vgoto(WECHO, 0);
putchar(c);
vclreol();
vgoto(WECHO, 1);
cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
if (peekbr()) {
if (!INS[0] || (INS[0] & (QUOTE|TRIM)) == OVERBUF)
goto blewit;
vglobp = INS;
}
OP = Pline; Pline = normline;
ignore(vgetline(0, genbuf + 1, &waste, c));
if (Outchar == termchar)
putchar('\n');
vscrap();
Pline = OP;
if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) {
cursor = sc;
vclreol();
return (0);
}
blewit:
OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0;
splitw = 0;
vclean();
vshow(dot, NOLINE);
vnline(sc);
Peekkey = OPeek;
return (1);
}
 
/*
* A complete command has been defined for
* the purposes of repeat, so copy it from
* the working to the previous command buffer.
*/
void
setLAST(void)
{
 
if (vglobp || vmacp)
return;
lastreg = vreg;
lasthad = Xhadcnt;
lastcnt = Xcnt;
*lastcp = 0;
cellcpy(lastcmd, workcmd);
}
 
/*
* Gather up some more text from an insert.
* If the insertion buffer oveflows, then destroy
* the repeatability of the insert.
*/
void
addtext(char *cp)
{
 
if (vglobp)
return;
addto(INS, cp);
if ((INS[0] & (QUOTE|TRIM)) == OVERBUF)
lastcmd[0] = 0;
}
 
void
setDEL(void)
{
 
setBUF(DEL);
}
 
/*
* Put text from cursor upto wcursor in BUF.
*/
void
setBUF(register cell *BUF)
{
register int c;
register char *wp = wcursor;
 
c = *wp;
*wp = 0;
BUF[0] = 0;
addto(BUF, cursor);
*wp = c;
}
 
void
addto(register cell *buf, register char *str)
{
 
if ((buf[0] & (QUOTE|TRIM)) == OVERBUF)
return;
if (cellen(buf) + strlen(str) + 1 >= VBSIZE) {
buf[0] = OVERBUF;
return;
}
while (*buf)
buf++;
str2cell(buf, str);
}
 
/*
* Note a change affecting a lot of lines, or non-visible
* lines. If the parameter must is set, then we only want
* to do this for open modes now; return and save for later
* notification in visual.
*/
int
noteit(int must)
{
register int sdl = destline, sdc = destcol;
 
if (notecnt < 2 || !must && state == VISUAL)
return (0);
splitw++;
if (WBOT == WECHO)
vmoveitup(1, 1);
vigoto(WECHO, 0);
printf(catgets(catd, 1, 223, "%d %sline"), notecnt, notesgn);
if (notecnt > 1)
putchar('s');
if (*notenam) {
printf(" %s", notenam);
if (*(strend(notenam) - 1) != 'e')
putchar('e');
putchar('d');
}
vclreol();
notecnt = 0;
if (state != VISUAL)
vcnt = vcline = 0;
splitw = 0;
if (state == ONEOPEN || state == CRTOPEN)
vup1();
destline = sdl; destcol = sdc;
return (1);
}
 
/*
* Rrrrringgggggg.
* If possible, use flash (VB).
*/
void
beep(void)
{
 
if (VB && value(FLASH))
vputp(VB, 0);
else
vputc(CTRL('g'));
}
 
/*
* Push an integer string as a macro.
*/
static void
imacpush(int *ip, int canundo)
{
char buf[BUFSIZ], *bp = buf;
 
#ifdef MB
do {
int n;
n = wctomb(bp, *ip&TRIM);
bp += n;
} while (*ip++);
#else /* !MB */
while (*bp++ = *ip++);
#endif /* !MB */
macpush(buf, canundo);
}
 
/*
* Map the command input character c,
* for keypads and labelled keys which do cursor
* motions. I.e. on an adm3a we might map ^K to ^P.
* DM1520 for example has a lot of mappable characters.
*/
 
int
map(register int c, register struct maps *maps)
{
register int d;
register int *p, *q;
int b[10+MB_LEN_MAX]; /* Assumption: no keypad sends string longer than 10 */
 
/*
* Mapping for special keys on the terminal only.
* BUG: if there's a long sequence and it matches
* some chars and then misses, we lose some chars.
*
* For this to work, some conditions must be met.
* 1) Keypad sends SHORT (2 or 3 char) strings
* 2) All strings sent are same length & similar
* 3) The user is unlikely to type the first few chars of
* one of these strings very fast.
* Note: some code has been fixed up since the above was laid out,
* so conditions 1 & 2 are probably not required anymore.
* However, this hasn't been tested with any first char
* that means anything else except escape.
*/
#ifdef MDEBUG
if (trace)
fprintf(trace,"map(%c): ",c);
#endif
/*
* If c==0, the char came from getesc typing escape. Pass it through
* unchanged. 0 messes up the following code anyway.
*/
if (c==0)
return(0);
 
b[0] = c;
b[1] = 0;
for (d=0; maps[d].mapto; d++) {
#ifdef MDEBUG
if (trace)
fprintf(trace,"\ntry '%s', ",maps[d].cap);
#endif
if (p = maps[d].icap) {
for (q=b; *p; p++, q++) {
#ifdef MDEBUG
if (trace)
fprintf(trace,"q->b[%d], ",q-b);
#endif
if (*q==0) {
/*
* Is there another char waiting?
*
* This test is oversimplified, but
* should work mostly. It handles the
* case where we get an ESCAPE that
* wasn't part of a keypad string.
*/
if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
#ifdef MDEBUG
if (trace)
fprintf(trace,"fpk=0: will return '%c'",c);
#endif
/*
* Nothing waiting. Push back
* what we peeked at & return
* failure (c).
*
* We want to be able to undo
* commands, but it's nonsense
* to undo part of an insertion
* so if in input mode don't.
*/
#ifdef MDEBUG
if (trace)
fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
#endif
imacpush(&b[1],maps == arrows);
#ifdef MDEBUG
if (trace)
fprintf(trace, "return %d\n", c);
#endif
return(c);
}
*q = getkey();
q[1] = 0;
}
if (*p != *q)
goto contin;
}
macpush(maps[d].mapto,maps == arrows);
c = getkey();
#ifdef MDEBUG
if (trace)
fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
#endif
return(c); /* first char of map string */
contin:;
}
}
#ifdef MDEBUG
if (trace)
fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
#endif
imacpush(&b[1],0);
return(c);
}
 
/*
* Push st onto the front of vmacp. This is tricky because we have to
* worry about where vmacp was previously pointing. We also have to
* check for overflow (which is typically from a recursive macro)
* Finally we have to set a flag so the whole thing can be undone.
* canundo is 1 iff we want to be able to undo the macro. This
* is false for, for example, pushing back lookahead from fastpeekkey(),
* since otherwise two fast escapes can clobber our undo.
*/
void
macpush(char *st, int canundo)
{
char tmpbuf[BUFSIZ];
 
if (st==0 || *st==0)
return;
#ifdef MDEBUG
if (trace)
fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
#endif
if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ)
error(catgets(catd, 1, 224,
"Macro too long@ - maybe recursive?"));
if (vmacp) {
strcpy(tmpbuf, vmacp);
if (!FIXUNDO)
canundo = 0; /* can't undo inside a macro anyway */
}
strcpy(vmacbuf, st);
if (vmacp)
strcat(vmacbuf, tmpbuf);
vmacp = vmacbuf;
/* arrange to be able to undo the whole macro */
if (canundo) {
#ifdef notdef
otchng = tchng;
vsave();
saveall();
inopen = -1; /* no need to save since it had to be 1 or -1 before */
vundkind = VMANY;
#endif
vch_mac = VC_NOCHANGE;
}
}
 
#ifdef TRACE
void
visdump(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<TUBELINES; i++)
if (vtube[i] && *vtube[i])
fprintf(trace, "%d: '%s'\n", i, vtube[i]);
tvliny();
}
 
void
vudump(char *s)
{
register line *p;
char savelb[1024];
 
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, " [\n");
CP(savelb, linebuf);
fprintf(trace, "linebuf = '%s'\n", linebuf);
for (p=zero+1; p<=truedol; p++) {
fprintf(trace, "%o ", *p);
getline(*p);
fprintf(trace, "'%s'\n", linebuf);
}
fprintf(trace, "]\n");
CP(linebuf, savelb);
}
#endif
 
/*
* Get a count from the keyed input stream.
* A zero count is indistinguishable from no count.
*/
int
vgetcnt(void)
{
register int c, cnt;
 
cnt = 0;
for (;;) {
c = getkey();
if (!xisdigit(c))
break;
cnt *= 10, cnt += c - '0';
}
ungetkey(c);
Xhadcnt = 1;
Xcnt = cnt;
return(cnt);
}
 
void
trapalarm(int signum) {
alarm(0);
if (vcatch)
LONGJMP(vreslab,1);
}
 
/*
* fastpeekkey is just like peekkey but insists the character come in
* fast (within 1 second). This will succeed if it is the 2nd char of
* a machine generated sequence (such as a function pad from an escape
* flavor terminal) but fail for a human hitting escape then waiting.
*/
int
fastpeekkey(void)
{
shand Oint;
register int c;
 
/*
* If the user has set notimeout, we wait forever for a key.
* If we are in a macro we do too, but since it's already
* buffered internally it will return immediately.
* In other cases we force this to die in 1 second.
* This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
* but UNIX truncates it to 0 - 1 secs) but due to system delays
* there are times when arrow keys or very fast typing get counted
* as separate. notimeout is provided for people who dislike such
* nondeterminism.
*/
#ifdef MDEBUG
if (trace)
fprintf(trace,"\nfastpeekkey: ",c);
#endif
Oint = signal(SIGINT, trapalarm);
if (value(TIMEOUT) && inopen >= 0) {
signal(SIGALRM, trapalarm);
#ifdef MDEBUG
alarm(10);
if (trace)
fprintf(trace, "set alarm ");
#else
alarm(1);
#endif
}
CATCH
c = peekkey();
#ifdef MDEBUG
if (trace)
fprintf(trace,"[OK]",c);
#endif
alarm(0);
ONERR
c = 0;
#ifdef MDEBUG
if (trace)
fprintf(trace,"[TIMEOUT]",c);
#endif
ENDCATCH
#ifdef MDEBUG
if (trace)
fprintf(trace,"[fpk:%o]",c);
#endif
signal(SIGINT,Oint);
return(c);
}
/ports/trunk/editors/exvi/ex_voper.c
0,0 → 1,976
/*
* 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_voper.c 1.27 (gritter) 2/15/05";
#endif
#endif
 
/* from ex_voper.c 7.4 (Berkeley) 6/7/85 */
 
#include "ex.h"
#include "ex_re.h"
#include "ex_tty.h"
#include "ex_vis.h"
 
#ifdef MB
static int
cblank(char *cp)
{
if (mb_cur_max > 1 && *cp & 0200) {
int c;
return mbtowi(&c, cp, mb_cur_max) > 0 && iswspace(c);
} else
return isspace(*cp&0377);
}
#define blank() cblank(wcursor)
#else /* !MB */
#define cblank(cp) isspace(*cp&0377)
#define blank() xisspace(wcursor[0]&TRIM)
#endif /* !MB */
#define forbid(a) if (a) goto errlab;
 
cell vscandir[2] = { '/', 0 };
 
/*
* Decode an operator/operand type command.
* Eventually we switch to an operator subroutine in ex_vops.c.
* The work here is setting up a function variable to point
* to the routine we want, and manipulation of the variables
* wcursor and wdot, which mark the other end of the affected
* area. If wdot is zero, then the current line is the other end,
* and if wcursor is zero, then the first non-blank location of the
* other line is implied.
*/
void
operate(register int c, register int cnt)
{
register int i = 0;
void (*moveop)(int), (*deleteop)(int);
void (*opf)(int);
bool subop = 0;
char *oglobp, *ocurs;
register line *addr;
line *odot;
static int lastFKND, lastFCHR;
short d;
cell nullcell[1], qmarkcell[2], slashcell[2];
 
CLOBBGRD(opf);
CLOBBGRD(d);
qmarkcell[0] = '?';
slashcell[0] = '/';
nullcell[0] = qmarkcell[1] = slashcell[1] = 0;
moveop = vmove, deleteop = vdelete;
wcursor = cursor;
wdot = NOLINE;
notecnt = 0;
dir = 1;
switch (c) {
 
/*
* d delete operator.
*/
case 'd':
moveop = vdelete;
deleteop = (void (*)(int))beep;
break;
 
/*
* s substitute characters, like c\040, i.e. change space.
*/
case 's':
ungetkey(' ');
subop++;
/* fall into ... */
 
/*
* c Change operator.
*/
case 'c':
if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S')
subop++;
moveop = vchange;
deleteop = (void (*)(int))beep;
break;
 
/*
* ! Filter through a UNIX command.
*/
case '!':
moveop = vfilter;
deleteop = (void (*)(int))beep;
break;
 
/*
* y Yank operator. Place specified text so that it
* can be put back with p/P. Also yanks to named buffers.
*/
case 'y':
moveop = vyankit;
deleteop = (void (*)(int))beep;
break;
 
/*
* = Reformat operator (for LISP).
*/
#ifdef LISPCODE
case '=':
forbid(!value(LISP));
/* fall into ... */
#endif
 
/*
* > Right shift operator.
* < Left shift operator.
*/
case '<':
case '>':
moveop = vshftop;
deleteop = (void (*)(int))beep;
break;
 
/*
* r Replace character under cursor with single following
* character.
*/
case 'r':
vmacchng(1);
vrep(cnt);
return;
 
default:
goto nocount;
}
vmacchng(1);
/*
* Had an operator, so accept another count.
* Multiply counts together.
*/
if (xisdigit(peekkey()) && peekkey() != '0') {
cnt *= vgetcnt();
Xcnt = cnt;
forbid (cnt <= 0);
}
 
/*
* Get next character, mapping it and saving as
* part of command for repeat.
*/
c = map(getesc(),arrows);
if (c == 0)
return;
if (!subop)
*lastcp++ = c;
nocount:
opf = moveop;
switch (c) {
 
/*
* b Back up a word.
* B Back up a word, liberal definition.
*/
case 'b':
case 'B':
dir = -1;
/* fall into ... */
 
/*
* w Forward a word.
* W Forward a word, liberal definition.
*/
case 'W':
case 'w':
wdkind = c & ' ';
forbid(llfind(2, cnt, opf, 0) < 0);
vmoving = 0;
break;
 
/*
* E to end of following blank/nonblank word
*/
case 'E':
wdkind = 0;
goto ein;
 
/*
* e To end of following word.
*/
case 'e':
wdkind = 1;
ein:
forbid(llfind(3, cnt - 1, opf, 0) < 0);
vmoving = 0;
break;
 
/*
* ( Back an s-expression.
*/
case '(':
dir = -1;
/* fall into... */
 
/*
* ) Forward an s-expression.
*/
case ')':
forbid(llfind(0, cnt, opf, (line *) 0) < 0);
markDOT();
break;
 
/*
* { Back an s-expression, but don't stop on atoms.
* In text mode, a paragraph. For C, a balanced set
* of {}'s.
*/
case '{':
dir = -1;
/* fall into... */
 
/*
* } Forward an s-expression, but don't stop on atoms.
* In text mode, back paragraph. For C, back a balanced
* set of {}'s.
*/
case '}':
forbid(llfind(1, cnt, opf, (line *) 0) < 0);
markDOT();
break;
 
/*
* % To matching () or {}. If not at ( or { scan for
* first such after cursor on this line.
*/
case '%':
vsave();
i = lmatchp((line *) 0);
#ifdef TRACE
if (trace)
fprintf(trace, "after lmatchp in %, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
#endif
getDOT();
forbid(!i);
if (opf != vmove)
if (dir > 0)
wcursor += skipright(linebuf, wcursor);
else
cursor += skipright(linebuf, cursor);
else
markDOT();
vmoving = 0;
break;
 
/*
* [ Back to beginning of defun, i.e. an ( in column 1.
* For text, back to a section macro.
* For C, back to a { in column 1 (~~ beg of function.)
*/
case '[':
dir = -1;
/* fall into ... */
 
/*
* ] Forward to next defun, i.e. a ( in column 1.
* For text, forward section.
* For C, forward to a } in column 1 (if delete or such)
* or if a move to a { in column 1.
*/
case ']':
if (!vglobp)
forbid(getkey() != c);
forbid (Xhadcnt);
vsave();
i = lbrack(c, opf);
getDOT();
forbid(!i);
markDOT();
if (ospeed > B300)
hold |= HOLDWIG;
break;
 
/*
* , Invert last find with f F t or T, like inverse
* of ;.
*/
case ',':
forbid (lastFKND == 0);
c = xisupper(lastFKND&TRIM)
? xtolower(lastFKND&TRIM) : xtoupper(lastFKND&TRIM);
i = lastFCHR;
if (vglobp == 0)
vglobp = nullcell;
subop++;
goto nocount;
 
/*
* 0 To beginning of real line.
*/
case '0':
wcursor = linebuf;
vmoving = 0;
break;
 
/*
* ; Repeat last find with f F t or T.
*/
case ';':
forbid (lastFKND == 0);
c = lastFKND;
i = lastFCHR;
subop++;
goto nocount;
 
/*
* F Find single character before cursor in current line.
* T Like F, but stops before character.
*/
case 'F': /* inverted find */
case 'T':
dir = -1;
/* fall into ... */
 
/*
* f Find single character following cursor in current line.
* t Like f, but stope before character.
*/
case 'f': /* find */
case 't':
if (!subop) {
i = getesc();
if (i == 0)
return;
*lastcp++ = i;
}
if (vglobp == 0)
lastFKND = c, lastFCHR = i;
for (; cnt > 0; cnt--)
forbid (find(i) == 0);
vmoving = 0;
switch (c) {
 
case 'T':
wcursor += skipright(linebuf, wcursor);
break;
 
case 't':
wcursor += skipleft(linebuf, wcursor);
case 'f':
fixup:
if (moveop != vmove)
wcursor += skipright(linebuf, wcursor);
break;
}
break;
 
/*
* | Find specified print column in current line.
*/
case '|':
if (Pline == numbline)
cnt += 8;
vmovcol = cnt;
vmoving = 1;
wcursor = vfindcol(cnt);
break;
 
/*
* ^ To beginning of non-white space on line.
*/
case '^':
wcursor = vskipwh(linebuf);
vmoving = 0;
break;
 
/*
* $ To end of line.
*/
case '$':
if (opf == vmove) {
vmoving = 1;
vmovcol = 20000;
} else
vmoving = 0;
if (cnt > 1) {
if (opf == vmove) {
wcursor = 0;
cnt--;
} else
wcursor = linebuf;
/* This is wrong at EOF */
wdot = dot + cnt;
break;
}
if (linebuf[0]) {
wcursor = strend(linebuf) - 1;
goto fixup;
}
wcursor = linebuf;
break;
 
/*
* h Back a character.
* ^H Back a character.
*/
case 'h':
case CTRL('h'):
dir = -1;
/* fall into ... */
 
/*
* space Forward a character.
*/
case 'l':
case ' ':
forbid (margin() || opf == vmove && edge());
while (cnt > 0 && !margin()) {
wcursor += dir>0 ? skipright(linebuf, wcursor) :
skipleft(linebuf, wcursor);
cnt--;
}
if (margin() && opf == vmove || wcursor < linebuf)
wcursor -= dir;
vmoving = 0;
break;
 
/*
* D Delete to end of line, short for d$.
*/
case 'D':
cnt = INF;
goto deleteit;
 
/*
* X Delete character before cursor.
*/
case 'X':
dir = -1;
/* fall into ... */
deleteit:
/*
* x Delete character at cursor, leaving cursor where it is.
*/
case 'x':
if (margin())
goto errlab;
vmacchng(1);
while (cnt > 0 && !margin()) {
wcursor += dir > 0 ? skipright(linebuf, wcursor) :
skipleft(linebuf, wcursor);
cnt--;
}
opf = deleteop;
vmoving = 0;
break;
 
default:
/*
* Stuttered operators are equivalent to the operator on
* a line, thus turn dd into d_.
*/
if (opf == vmove || c != workcmd[0]) {
errlab:
beep();
vmacp = 0;
return;
}
/* fall into ... */
 
/*
* _ Target for a line or group of lines.
* Stuttering is more convenient; this is mostly
* for aesthetics.
*/
case '_':
wdot = dot + cnt - 1;
vmoving = 0;
wcursor = 0;
break;
 
/*
* H To first, home line on screen.
* Count is for count'th line rather than first.
*/
case 'H':
wdot = (dot - vcline) + cnt - 1;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
 
/*
* - Backwards lines, to first non-white character.
*/
case '-':
wdot = dot - cnt;
vmoving = 0;
wcursor = 0;
break;
 
/*
* ^P To previous line same column. Ridiculous on the
* console of the VAX since it puts console in LSI mode.
*/
case 'k':
case CTRL('p'):
wdot = dot - cnt;
if (vmoving == 0)
vmoving = 1, vmovcol = lcolumn(cursor);
wcursor = 0;
break;
 
/*
* L To last line on screen, or count'th line from the
* bottom.
*/
case 'L':
wdot = dot + vcnt - vcline - cnt;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
 
/*
* M To the middle of the screen.
*/
case 'M':
wdot = dot + ((vcnt + 1) / 2) - vcline - 1;
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
 
/*
* + Forward line, to first non-white.
*
* CR Convenient synonym for +.
*/
case '+':
case CR:
wdot = dot + cnt;
vmoving = 0;
wcursor = 0;
break;
 
/*
* ^N To next line, same column if possible.
*
* LF Linefeed is a convenient synonym for ^N.
*/
case CTRL('n'):
case 'j':
case NL:
wdot = dot + cnt;
if (vmoving == 0)
vmoving = 1, vmovcol = lcolumn(cursor);
wcursor = 0;
break;
 
/*
* n Search to next match of current pattern.
*/
case 'n':
vglobp = vscandir;
c = *vglobp++;
goto nocount;
 
/*
* N Like n but in reverse direction.
*/
case 'N':
vglobp = vscandir[0] == '/' ? qmarkcell : slashcell;
c = *vglobp++;
goto nocount;
 
/*
* ' Return to line specified by following mark,
* first white position on line.
*
* ` Return to marked line at remembered column.
*/
case '\'':
case '`':
d = c;
c = getesc();
if (c == 0)
return;
c = markreg(c);
forbid (c == 0);
wdot = getmark(c);
forbid (wdot == NOLINE);
forbid (Xhadcnt);
vmoving = 0;
wcursor = d == '`' ? ncols[c - 'a'] : 0;
if (opf == vmove && (wdot != dot || (d == '`' && wcursor != cursor)))
markDOT();
if (wcursor) {
vsave();
getline(*wdot);
if (wcursor > strend(linebuf))
wcursor = 0;
getDOT();
}
if (ospeed > B300)
hold |= HOLDWIG;
break;
 
/*
* G Goto count'th line, or last line if no count
* given.
*/
case 'G':
if (!Xhadcnt)
cnt = lineDOL();
wdot = zero + cnt;
forbid (wdot < one || wdot > dol);
if (opf == vmove)
markit(wdot);
vmoving = 0;
wcursor = 0;
break;
 
/*
* / Scan forward for following re.
* ? Scan backward for following re.
*/
case '/':
case '?':
forbid (Xhadcnt);
vsave();
ocurs = cursor;
odot = dot;
wcursor = 0;
if (readecho(c))
return;
if (!vglobp)
vscandir[0] = genbuf[0];
oglobp = globp;
CP(vutmp, genbuf);
globp = vutmp;
d = peekc;
fromsemi:
ungetchar(0);
fixech();
CATCH
addr = address(cursor);
ONERR
slerr:
globp = oglobp;
dot = odot;
cursor = ocurs;
ungetchar(d);
splitw = 0;
vclean();
vjumpto(dot, ocurs, 0);
return;
ENDCATCH
if (globp == 0)
globp = "";
else if (peekc)
--globp;
if (*globp == ';') {
/* /foo/;/bar/ */
globp++;
dot = addr;
cursor = loc1;
goto fromsemi;
}
dot = odot;
ungetchar(d);
c = 0;
if (*globp == 'z')
globp++, c = '\n';
if (any(*globp, "^+-."))
c = *globp++;
i = 0;
while (xisdigit(*globp&TRIM))
i = i * 10 + *globp++ - '0';
if (any(*globp, "^+-."))
c = *globp++;
if (*globp) {
/* random junk after the pattern */
beep();
goto slerr;
}
globp = oglobp;
splitw = 0;
vmoving = 0;
wcursor = loc1;
if (i != 0)
vsetsiz(i);
if (opf == vmove) {
if (state == ONEOPEN || state == HARDOPEN)
outline = destline = WBOT;
if (addr != dot || loc1 != cursor)
markDOT();
if (loc1 > linebuf && *loc1 == 0)
loc1--;
if (c)
vjumpto(addr, loc1, c);
else {
vmoving = 0;
if (loc1) {
vmoving++;
vmovcol = column(loc1);
}
getDOT();
if (state == CRTOPEN && addr != dot)
vup1();
vupdown(addr - dot, NOSTR);
}
return;
}
lastcp[-1] = 'n';
getDOT();
wdot = addr;
break;
}
/*
* Apply.
*/
if (vreg && wdot == 0)
wdot = dot;
(*opf)(c);
wdot = NOLINE;
}
 
/*
* Find single character c, in direction dir from cursor.
*/
int
find(int c)
{
 
for(;;) {
if (edge())
return (0);
wcursor += dir>0 ? skipright(linebuf, wcursor) :
skipleft(linebuf, wcursor-1);
if (samechar(wcursor, c))
return (1);
}
}
 
/*
* Do a word motion with operator op, and cnt more words
* to go after this.
*/
int
word(register void (*op)(int), int cnt)
{
register int which = 0, i;
register char *iwc;
register line *iwdot = wdot;
 
if (dir == 1) {
iwc = wcursor;
which = wordch(wcursor);
while (wordof(which, wcursor)) {
if (cnt == 1 && op != vmove &&
wcursor[i = skipright(linebuf, wcursor)]
== 0) {
wcursor += i;
break;
}
if (!lnext())
return (0);
if (wcursor == linebuf)
break;
}
/* Unless last segment of a change skip blanks */
if (op != vchange || cnt > 1)
while (!margin() && blank())
wcursor += skipright(linebuf, wcursor);
else
if (wcursor == iwc && iwdot == wdot && *iwc)
wcursor += skipright(linebuf, wcursor);
if (op == vmove && margin()) {
if (wcursor == linebuf)
wcursor--;
else if (!lnext())
return (0);
}
} else {
if (!lnext())
return (0);
while (blank())
if (!lnext())
return (0);
if (!margin()) {
which = wordch(wcursor);
while (!margin() && wordof(which, wcursor))
wcursor--;
}
if (wcursor < linebuf || !wordof(which, wcursor))
wcursor += skipright(linebuf, wcursor);
}
return (1);
}
 
/*
* To end of word, with operator op and cnt more motions
* remaining after this.
*/
void
eend(register void (*op)(int))
{
register int which;
 
if (!lnext())
return;
while (blank())
if (!lnext())
return;
which = wordch(wcursor);
while (wordof(which, wcursor)) {
if (wcursor[1] == 0) {
wcursor++;
break;
}
if (!lnext())
return;
}
if (op != vchange && op != vdelete && wcursor > linebuf)
wcursor--;
}
 
/*
* Wordof tells whether the character at *wc is in a word of
* kind which (blank/nonblank words are 0, conservative words 1).
*/
int
wordof(int which, register char *wc)
{
 
if (cblank(wc))
return (0);
return (!wdkind || wordch(wc) == which);
}
 
/*
* Wordch tells whether character at *wc is a word character
* i.e. an alfa, digit, or underscore.
*/
int
wordch(char *wc)
{
int c;
 
#ifdef MB
if (mb_cur_max > 0 && *wc & 0200) {
mbtowi(&c, wc, mb_cur_max);
if (c & INVBIT)
return 1;
} else
#endif
c = wc[0]&0377;
return (xisalnum(c) || c == '_'
#ifdef BIT8
#ifdef ISO8859_1
/*
* We consider all ISO 8859-1 characters except for
* no-break-space as word characters.
*/
|| c&0200 && (!(c&QUOTE) && (c&TRIM) != 0240)
#endif
#endif
);
}
 
/*
* Edge tells when we hit the last character in the current line.
*/
int
edge(void)
{
 
if (linebuf[0] == 0)
return (1);
if (dir == 1)
return (wcursor[skipright(linebuf, wcursor)] == 0);
else
return (wcursor == linebuf);
}
 
/*
* Margin tells us when we have fallen off the end of the line.
*/
int
margin(void)
{
 
return (wcursor < linebuf || wcursor[0] == 0);
}
/ports/trunk/editors/exvi/ex_vops3.c
0,0 → 1,730
/*
* 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_vops3.c 1.19 (gritter) 1/2/05";
#endif
#endif
 
/* from ex_vops3.c 7.3 (Berkeley) 6/7/85 */
 
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
 
/*
* Routines to handle structure.
* Operations supported are:
* ( ) { } [ ]
*
* These cover: LISP TEXT
* ( ) s-exprs sentences
* { } list at same paragraphs
* [ ] defuns sections
*
* { and } for C used to attempt to do something with matching {}'s, but
* I couldn't find definitions which worked intuitively very well, so I
* scrapped this.
*
* The code here is very hard to understand.
*/
line *llimit;
void (*lf)(int);
 
bool wasend;
 
/*
* Find over structure, repeated count times.
* Don't go past line limit. F is the operation to
* be performed eventually. If pastatom then the user said {}
* rather than (), implying past atoms in a list (or a paragraph
* rather than a sentence.
*/
int
llfind(bool pastatom, int cnt, void (*f)(int), line *limit)
{
#ifdef LISPCODE
register int c;
#endif
register int rc = 0;
char save[LBSIZE];
 
/*
* Initialize, saving the current line buffer state
* and computing the limit; a 0 argument means
* directional end of file.
*/
wasend = 0;
lf = f;
strcpy(save, linebuf);
if (limit == 0)
limit = dir < 0 ? one : dol;
llimit = limit;
wdot = dot;
wcursor = cursor;
 
if (pastatom >= 2) {
while (cnt > 0 && word(f, cnt))
cnt--;
if (pastatom == 3)
eend(f);
if (dot == wdot) {
wdot = 0;
if (cursor == wcursor)
rc = -1;
}
}
#ifdef LISPCODE
else if (!value(LISP)) {
#else
else {
#endif
char *icurs;
line *idot;
 
if (linebuf[0] == 0) {
do
if (!lnext())
goto ret;
while (linebuf[0] == 0);
if (dir > 0) {
wdot--;
linebuf[0] = 0;
wcursor = linebuf;
/*
* If looking for sentence, next line
* starts one.
*/
if (!pastatom) {
icurs = wcursor;
idot = wdot;
goto begin;
}
}
}
icurs = wcursor;
idot = wdot;
 
/*
* Advance so as to not find same thing again.
*/
if (dir > 0) {
if (!lnext()) {
rc = -1;
goto ret;
}
} else
ignore(lskipa1(""));
 
/*
* Count times find end of sentence/paragraph.
*/
begin:
for (;;) {
while (!endsent(pastatom))
if (!lnext())
goto ret;
if (!pastatom || wcursor == linebuf && endPS())
if (--cnt <= 0)
break;
if (linebuf[0] == 0) {
do
if (!lnext())
goto ret;
while (linebuf[0] == 0);
} else
if (!lnext())
goto ret;
}
 
/*
* If going backwards, and didn't hit the end of the buffer,
* then reverse direction.
*/
if (dir < 0 && (wdot != llimit || wcursor != linebuf)) {
dir = 1;
llimit = dot;
/*
* Empty line needs special treatement.
* If moved to it from other than begining of next line,
* then a sentence starts on next line.
*/
if (linebuf[0] == 0 && !pastatom &&
(wdot != dot - 1 || cursor != linebuf)) {
lnext();
goto ret;
}
}
 
/*
* If we are not at a section/paragraph division,
* advance to next.
*/
if (wcursor == icurs && wdot == idot || wcursor != linebuf || !endPS())
ignore(lskipa1(""));
}
#ifdef LISPCODE
else {
c = *wcursor;
/*
* Startup by skipping if at a ( going left or a ) going
* right to keep from getting stuck immediately.
*/
if (dir < 0 && c == '(' || dir > 0 && c == ')') {
if (!lnext()) {
rc = -1;
goto ret;
}
}
/*
* Now chew up repitition count. Each time around
* if at the beginning of an s-exp (going forwards)
* or the end of an s-exp (going backwards)
* skip the s-exp. If not at beg/end resp, then stop
* if we hit a higher level paren, else skip an atom,
* counting it unless pastatom.
*/
while (cnt > 0) {
c = *wcursor;
if (dir < 0 && c == ')' || dir > 0 && c == '(') {
if (!lskipbal("()"))
goto ret;
/*
* Unless this is the last time going
* backwards, skip past the matching paren
* so we don't think it is a higher level paren.
*/
if (dir < 0 && cnt == 1)
goto ret;
if (!lnext() || !ltosolid())
goto ret;
--cnt;
} else if (dir < 0 && c == '(' || dir > 0 && c == ')')
/* Found a higher level paren */
goto ret;
else {
if (!lskipatom())
goto ret;
if (!pastatom)
--cnt;
}
}
}
#endif
ret:
strcLIN(save);
return (rc);
}
 
/*
* Is this the end of a sentence?
*/
int
endsent(bool pastatom)
{
register char *cp = wcursor;
register int c, d;
 
/*
* If this is the beginning of a line, then
* check for the end of a paragraph or section.
*/
if (cp == linebuf)
return (endPS());
 
/*
* Sentences end with . ! ? not at the beginning
* of the line, and must be either at the end of the line,
* or followed by 2 spaces. Any number of intervening ) ] ' "
* characters are allowed.
*/
if (!any(c = *cp, ".!?"))
goto tryps;
do
if ((d = *++cp) == 0)
return (1);
while (any(d, ")]'"));
if (*cp == 0 || *cp++ == ' ' && *cp == ' ')
return (1);
tryps:
if (cp[1] == 0)
return (endPS());
return (0);
}
 
/*
* End of paragraphs/sections are respective
* macros as well as blank lines and form feeds.
*/
int
endPS(void)
{
 
return (linebuf[0] == 0 ||
isa(svalue(PARAGRAPHS)) || isa(svalue(SECTIONS)));
}
 
#ifdef LISPCODE
int
lindent(line *addr)
{
register int i;
char *swcurs = wcursor;
line *swdot = wdot;
 
again:
if (addr > one) {
register char *cp;
register int cnt = 0;
 
addr--;
getline(*addr);
for (cp = linebuf; *cp; cp++)
if (*cp == '(')
cnt++;
else if (*cp == ')')
cnt--;
cp = vpastwh(linebuf);
if (*cp == 0)
goto again;
if (cnt == 0)
return (whitecnt(linebuf));
addr++;
}
wcursor = linebuf;
linebuf[0] = 0;
wdot = addr;
dir = -1;
llimit = one;
lf = (void (*)(int))lindent;
if (!lskipbal("()"))
i = 0;
else if (wcursor == linebuf)
i = 2;
else {
register char *wp = wcursor;
 
dir = 1;
llimit = wdot;
if (!lnext() || !ltosolid() || !lskipatom()) {
wcursor = wp;
i = 1;
} else
i = 0;
i += column(wcursor) - 1;
if (!inopen)
i--;
}
wdot = swdot;
wcursor = swcurs;
return (i);
}
#endif
 
int
lmatchp(line *addr)
{
register int i;
register char *parens, *cp;
 
for (cp = cursor; !any(*cp, "({[)}]");)
if (*cp++ == 0)
return (0);
lf = 0;
parens = any(*cp, "()") ? "()" : any(*cp, "[]") ? "[]" : "{}";
if (*cp == parens[1]) {
dir = -1;
llimit = one;
} else {
dir = 1;
llimit = dol;
}
if (addr)
llimit = addr;
if (splitw)
llimit = dot;
wcursor = cp;
wdot = dot;
i = lskipbal(parens);
return (i);
}
 
void
lsmatch(char *cp)
{
char save[LBSIZE];
register char *sp = save;
register char *scurs = cursor;
 
wcursor = cp;
strcpy(sp, linebuf);
*wcursor = 0;
strcpy(cursor, genbuf);
cursor = strend(linebuf) - 1;
if (lmatchp(dot - vcline)) {
register int i = insmode;
register int c = outcol;
register int l = outline;
 
if (!MI)
endim();
vgoto(splitw ? WECHO : LINE(wdot - llimit), column(wcursor) - 1);
flush();
sleep(1);
vgoto(l, c);
if (i)
goim();
}
else {
strcLIN(sp);
strcpy(scurs, genbuf);
if (!lmatchp((line *) 0))
beep();
}
strcLIN(sp);
wdot = 0;
wcursor = 0;
cursor = scurs;
}
 
int
ltosolid(void)
{
 
return (ltosol1("()"));
}
 
int
ltosol1(register char *parens)
{
register char *cp;
 
if (*parens && !*wcursor && !lnext())
return (0);
while (isspace(*wcursor&0377) || (*wcursor == 0 && *parens))
if (!lnext())
return (0);
if (any(*wcursor, parens) || dir > 0)
return (1);
for (cp = wcursor; cp > linebuf; cp--)
if (isspace(cp[-1]&0377) || any(cp[-1], parens))
break;
wcursor = cp;
return (1);
}
 
int
lskipbal(register char *parens)
{
register int level = dir;
register int c;
 
do {
if (!lnext()) {
wdot = NOLINE;
return (0);
}
c = *wcursor;
if (c == parens[1])
level--;
else if (c == parens[0])
level++;
} while (level);
return (1);
}
 
int
lskipatom(void)
{
 
return (lskipa1("()"));
}
 
int
lskipa1(register char *parens)
{
register int c;
 
for (;;) {
if (dir < 0 && wcursor == linebuf) {
if (!lnext())
return (0);
break;
}
c = *wcursor;
if (c && (isspace(c) || any(c, parens)))
break;
if (!lnext())
return (0);
if (dir > 0 && wcursor == linebuf)
break;
}
return (ltosol1(parens));
}
 
int
lnext(void)
{
 
if (dir > 0) {
if (*wcursor)
wcursor += skipright(linebuf, wcursor);
if (*wcursor)
return (1);
if (wdot >= llimit) {
if (lf == vmove && wcursor > linebuf)
wcursor += skipleft(linebuf, wcursor);
return (0);
}
wdot++;
getline(*wdot);
wcursor = linebuf;
return (1);
} else {
wcursor += skipleft(linebuf, wcursor);
if (wcursor >= linebuf)
return (1);
#ifdef LISPCODE
if (lf == (void (*)(int))lindent && linebuf[0] == '(')
llimit = wdot;
#endif
if (wdot <= llimit) {
wcursor = linebuf;
return (0);
}
wdot--;
getline(*wdot);
wcursor = linebuf[0] == 0 ? linebuf : strend(linebuf) - 1;
return (1);
}
}
 
int
lbrack(register int c, void (*f)(int))
{
register line *addr;
 
addr = dot;
for (;;) {
addr += dir;
if (addr < one || addr > dol) {
addr -= dir;
break;
}
getline(*addr);
if (linebuf[0] == '{' ||
#ifdef LISPCODE
value(LISP) && linebuf[0] == '(' ||
#endif
isa(svalue(SECTIONS))) {
if (c == ']' && f != vmove) {
addr--;
getline(*addr);
}
break;
}
if (c == ']' && f != vmove && linebuf[0] == '}')
break;
}
if (addr == dot)
return (0);
if (f != vmove)
wcursor = c == ']' ? strend(linebuf) : linebuf;
else
wcursor = 0;
wdot = addr;
vmoving = 0;
return (1);
}
 
int
isa(register char *cp)
{
 
if (linebuf[0] != '.')
return (0);
for (; cp[0] && cp[1]; cp += 2)
if (linebuf[1] == cp[0]) {
if (linebuf[2] == cp[1])
return (1);
if (linebuf[2] == 0 && cp[1] == ' ')
return (1);
}
return (0);
}
 
static void
cswitch(char *dst, int *dn, const char *src, int *sn)
{
int c;
 
#ifdef MB
if (mb_cur_max > 1) {
nextc(c, src, *sn);
if (c & INVBIT) {
*dst = *src;
*dn = *sn = 1;
} else {
if (iswupper(c))
c = towlower(c);
else if (iswlower(c))
c = towupper(c);
if ((*dn = wctomb(dst, c)) > *sn) {
*dst = *src;
*dn = *sn = 1;
}
}
} else
#endif /* MB */
{
c = *src & 0377;
if (isupper(c))
*dst = tolower(c);
else if (islower(c))
*dst = toupper(c);
else
*dst = c;
*dn = *sn = 1;
}
}
 
void
vswitch(int cnt)
{
if (cnt <= 1) {
char mbuf[MB_LEN_MAX+4];
int n0, n1;
setLAST();
mbuf[0] = 'r';
cswitch(&mbuf[1], &n1, cursor, &n0);
if (cursor[n1] != '\0')
mbuf[1+n1++] = ' ';
mbuf[1+n1] = '\0';
macpush(mbuf, 1);
} else { /* cnt > 1 */
char *mbuf = malloc(MAXDIGS + cnt*(mb_cur_max+1) + 5);
register char *p = &mbuf[MAXDIGS + 1];
int num, n0, n1, m;
 
setLAST();
*p++ = 's';
for (num = 0, m = 0; num < cnt && cursor[m] != '\0'; num++) {
*p++ = CTRL('v');
cswitch(p, &n1, &cursor[m], &n0);
p += n1;
m += n0;
}
*p++ = ESCAPE;
if (cursor[m])
*p++ = ' ';
*p++ = '\0';
macpush(p_dconv((long)num, mbuf), 1);
lastvgk = 0;
free(mbuf);
}
}
 
#ifdef MB
int
wskipleft(char *lp, char *pos)
{
int c, n;
 
do {
nextc(c, lp, n);
lp += n;
} while (lp < pos);
return -n;
}
 
int
wskipright(char *line, char *pos)
{
int c, n;
 
nextc(c, pos, n);
return n;
}
 
int
wsamechar(char *cp, int d)
{
int c;
 
if (mbtowi(&c, cp, mb_cur_max) >= 0 && c == d)
return 1;
return 0;
}
#endif /* MB */
/ports/trunk/editors/exvi/expreserve.c
0,0 → 1,555
/*
* 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.
*/
 
#ifdef __GNUC__
#define UNUSED __attribute__ ((unused))
#else
#define UNUSED
#endif
 
#ifndef lint
#ifdef DOSCCS
char *copyright =
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
All rights reserved.\n";
#endif
static char sccsid[] UNUSED = "@(#)expreserve.c 1.23 (gritter) 11/27/04";
#endif
 
/* from expreserve.c 7.13.2 (2.11BSD GTE) 1996/10/26 */
 
#include <stdio.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <dirent.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <time.h>
 
#include "config.h"
 
#ifdef LANGMSG
#include <nl_types.h>
#include <locale.h>
nl_catd catd;
#else
#define catgets(a, b, c, d) (d)
#endif
 
#ifdef BUFSIZ
#undef BUFSIZ
#endif
#ifdef LINE_MAX
#define BUFSIZ LINE_MAX /* POSIX line size */
#else /* !LINE_MAX */
#ifdef VMUNIX
#define BUFSIZ 1024
#else /* !VMUNIX */
#ifdef u370
#define BUFSIZ 4096
#else /* !u370 */
#define BUFSIZ 512
#endif /* !u370 */
#endif
#endif /* !VMUNIX */
 
#ifdef LARGEF
typedef off_t bloc;
#else
typedef short bloc;
#endif
 
#ifdef VMUNIX
#ifdef LARGEF
typedef off_t bbloc;
#else
typedef int bbloc;
#endif
#else
typedef short bbloc;
#endif
 
#ifdef notdef
#define TMP "/tmp"
#else
#define TMP "/var/tmp"
#endif
 
#ifndef VMUNIX
#define LBLKS 125
#else
#ifdef LARGEF
#define LBLKS 20000
#else
#define LBLKS 900
#endif
#endif
#ifdef _POSIX_PATH_MAX
#define FNSIZE _POSIX_PATH_MAX
#else
#define FNSIZE 128
#endif
 
#ifdef VMUNIX
#define HBLKS (1 + (FNSIZE + LBLKS * sizeof(bloc)) / BUFSIZ)
#else
#define HBLKS 1
#endif
 
char xstr[1]; /* make loader happy */
 
extern void notify(uid_t, char *, int, time_t);
extern int copyout(char *);
extern void mkdigits(char *);
extern void mknext(char *);
 
/*
* Expreserve - preserve a file in /usr/preserve
* Bill Joy UCB November 13, 1977
*
* This routine is very naive - it doesn't remove anything from
* /usr/preserve... this may mean that we leave
* stuff there... the danger in doing anything with /usr/preserve
* is that the clock may be screwed up and we may get confused.
*
* We are called in two ways - first from the editor with no argumentss
* and the standard input open on the temp file. Second with an argument
* to preserve the entire contents of /tmp (root only).
*
* BUG: should do something about preserving Rx... (register contents)
* temporaries.
*/
 
struct header {
time_t Time; /* Time temp file last updated */
uid_t Uid;
bbloc Flines; /* Number of lines in file */
char Savedfile[FNSIZE]; /* The current file name */
bloc Blocks[LBLKS]; /* Blocks where line pointers stashed */
} H;
 
#define ignore(a) a
#define ignorl(a) a
 
#define eq(a, b) (strcmp(a, b) == 0)
 
int
main(int argc, char **argv)
{
register DIR *tf;
struct dirent *dirent;
struct stat stbuf;
 
#ifdef LANGMSG
setlocale(LC_MESSAGES, "");
catd = catopen(CATNAME, NL_CAT_LOCALE);
#endif
/*
* If only one argument, then preserve the standard input.
*/
if (argc == 1) {
if (copyout((char *) 0))
exit(1);
exit(0);
}
 
/*
* If not super user, then can only preserve standard input.
*/
if (getuid()) {
fprintf(stderr, catgets(catd, 3, 1, "NOT super user\n"));
exit(1);
}
 
/*
* ... else preserve all the stuff in /tmp, removing
* it as we go.
*/
if (chdir(TMP) < 0) {
perror(TMP);
exit(1);
}
 
tf = opendir(".");
if (tf == NULL) {
perror(TMP);
exit(1);
}
while ((dirent = readdir(tf)) != NULL) {
/* Ex temporaries must begin with Ex. */
if (dirent->d_name[0] != 'E' || dirent->d_name[1] != 'x')
continue;
if (stat(dirent->d_name, &stbuf))
continue;
if ((stbuf.st_mode & S_IFMT) != S_IFREG)
continue;
/*
* Save the bastard.
*/
ignore(copyout(dirent->d_name));
}
closedir(tf);
return 0;
}
 
#ifdef notdef
char pattern[] = "/usr/preserve/Exaa`XXXXX";
#else
char pattern[] = "/var/preserve/Exa`XXXXXXXXXX";
#endif
 
/*
* Notify user uid that his file fname has been saved.
*/
void
notify(uid_t uid, char *fname, int flag, time_t time)
{
struct passwd *pp = getpwuid(uid);
register FILE *mf;
char cmd[BUFSIZ];
struct utsname ut;
char *hostname;
char croak[128];
char *timestamp;
 
if (pp == NULL)
return;
uname(&ut);
hostname = ut.nodename;
timestamp = ctime(&time);
timestamp[16] = 0; /* blast from seconds on */
putenv("MAILRC=/dev/null");
sprintf(cmd, "/bin/mail %s", pp->pw_name);
setuid(getuid());
mf = popen(cmd, "w");
if (mf == NULL)
return;
setbuf(mf, cmd);
/*
* flag says how the editor croaked:
* "the editor was killed" is perhaps still not an ideal
* error message. Usually, either it was forcably terminated
* or the phone was hung up, but we don't know which.
*/
sprintf(croak, flag
? catgets(catd, 3, 2, "the system went down")
: catgets(catd, 3, 3, "the editor was killed"));
if (fname[0] == 0) {
fname = "LOST";
fprintf(mf, catgets(catd, 3, 4,
"Subject: editor saved ``LOST''\n"));
fprintf(mf, catgets(catd, 3, 5,
"You were editing a file without a name\n"));
fprintf(mf, catgets(catd, 3, 6,
"at <%s> on the machine ``%s'' when %s.\n"),
timestamp, hostname, croak);
fprintf(mf, catgets(catd, 3, 7,
"Since the file had no name, it has been named \"LOST\".\n"));
} else {
fprintf(mf, catgets(catd, 3, 8,
"Subject: editor saved ``%s''\n"), fname);
fprintf(mf, catgets(catd, 3, 9,
"You were editing the file \"%s\"\n"), fname);
fprintf(mf, catgets(catd, 3, 10,
"at <%s> on the machine ``%s''\n"),
timestamp, hostname);
fprintf(mf, catgets(catd, 3, 11, "when %s.\n"), croak);
}
fprintf(mf, catgets(catd, 3, 12,
"\nYou can retrieve most of your changes to this file\n"));
fprintf(mf, catgets(catd, 3, 13,
"using the \"recover\" command of the editor.\n"));
fprintf(mf, catgets(catd, 3, 14,
"An easy way to do this is to give the command \"vi -r %s\".\n"), fname);
fprintf(mf, catgets(catd, 3, 15,
"This method also works using \"ex\" and \"edit\".\n"));
pclose(mf);
}
 
/*
* Copy file name into /usr/preserve/...
* If name is (char *) 0, then do the standard input.
* We make some checks on the input to make sure it is
* really an editor temporary, generate a name for the
* file (this is the slowest thing since we must stat
* to find a unique name), and finally copy the file.
*/
int
copyout(char *name)
{
int i;
char buf[BUFSIZ];
static int reenter;
 
/*
* The first time we put in the digits of our
* process number at the end of the pattern.
*/
if (reenter == 0) {
mkdigits(pattern);
reenter++;
}
 
/*
* If a file name was given, make it the standard
* input if possible.
*/
if (name != 0) {
ignore(close(0));
/*
* Need read/write access for arcane reasons
* (see below).
*/
if (open(name, O_RDWR) < 0)
return (-1);
}
 
/*
* Get the header block.
*/
ignorl(lseek(0, (off_t) 0, SEEK_SET));
if (read(0, (char *) &H, sizeof H) != sizeof H) {
format:
if (name == 0)
fprintf(stderr, catgets(catd, 3, 16,
"Buffer format error\t"));
return (-1);
}
 
/*
* Consistency checsks so we don't copy out garbage.
*/
if (H.Flines < 0) {
#ifdef DEBUG
fprintf(stderr, "Negative number of lines\n");
#endif
goto format;
}
if (H.Blocks[0] != HBLKS || H.Blocks[1] != HBLKS+1) {
#ifdef DEBUG
fprintf(stderr, "Blocks %d %d\n", H.Blocks[0], H.Blocks[1]);
#endif
goto format;
}
if (name == 0 && H.Uid != getuid()) {
#ifdef DEBUG
fprintf(stderr, "Wrong user-id\n");
#endif
goto format;
}
if (lseek(0, (off_t) 0, SEEK_SET)) {
#ifdef DEBUG
fprintf(stderr, "Negative number of lines\n");
#endif
goto format;
}
 
/*
* If no name was assigned to the file, then give it the name
* LOST, by putting this in the header.
*/
if (H.Savedfile[0] == 0) {
strcpy(H.Savedfile, "LOST");
ignore(write(0, (char *) &H, sizeof H));
H.Savedfile[0] = 0;
lseek(0, (off_t) 0, SEEK_SET);
}
 
/*
* File is good. Get a name and create a file for the copy.
*/
mknext(pattern);
ignore(close(1));
if (open(pattern, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC
#ifdef O_NOFOLLOW
|O_NOFOLLOW
#endif /* O_NOFOLLOW */
, 0600) < 0) {
if (name == 0)
perror(pattern);
return (1);
}
 
/*
* Make the target be owned by the owner of the file.
*/
ignore(chown(pattern, H.Uid, 0));
 
/*
* Copy the file.
*/
for (;;) {
i = read(0, buf, BUFSIZ);
if (i < 0) {
if (name)
perror(catgets(catd, 3, 17,
"Buffer read error"));
ignore(unlink(pattern));
return (-1);
}
if (i == 0) {
if (name)
ignore(unlink(name));
notify(H.Uid, H.Savedfile, name != 0, H.Time);
return (0);
}
if (write(1, buf, i) != i) {
if (name == 0)
perror(pattern);
unlink(pattern);
return (-1);
}
}
}
 
/*
* Blast the last 5 characters of cp to be the process number.
*/
void
mkdigits(char *cp)
{
register pid_t i;
register int j;
 
#ifdef notdef
for (i = getpid(), j = 5, cp += strlen(cp); j > 0; i /= 10, j--)
*--cp = i % 10 | '0';
#else
for (i = getpid(), j = 10, cp += strlen(cp); j > 0; i /= 10, j--)
*--cp = i % 10 | '0';
#endif
}
 
/*
* Make the name in cp be unique by clobbering up to
* three alphabetic characters into a sequence of the form 'aab', 'aac', etc.
* Mktemp gets weird names too quickly to be useful here.
*/
void
mknext(char *cp)
{
char *dcp;
struct stat stb;
 
dcp = cp + strlen(cp) - 1;
while (isdigit(*dcp & 0377))
dcp--;
whoops:
if (dcp[0] == 'z') {
dcp[0] = 'a';
if (dcp[-1] == 'z') {
#ifdef notdef
dcp[-1] = 'a';
if (dcp[-2] == 'z')
#endif
fprintf(stderr, catgets(catd, 3, 18,
"Can't find a name\t"));
#ifdef notdef
dcp[-2]++;
#endif
} else
dcp[-1]++;
} else
dcp[0]++;
if (stat(cp, &stb) == 0)
goto whoops;
}
 
/*
* people making love
* never exactly the same
* just like a snowflake
*/
 
#ifdef lint
void
Ignore(int a)
{
 
a = a;
}
 
void
Ignorl(long a)
{
 
a = a;
}
#endif
/ports/trunk/editors/exvi/libterm/libterm.h
0,0 → 1,56
/*
* 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.
*
*
* Header for termcap routines derived from 2.11 BSD.
*
* Sccsid @(#)libterm.h 1.4 (gritter) 11/23/04
*/
 
/*
* Size of the capability buffer string.
*/
#define TCBUFSIZE 2048
 
int tgetent(char *, const char *);
int tgetnum(char *);
int tgetflag(char *);
char *tgetstr(char *, char **);
char *tgoto(char *, int, int);
int tputs(const char *, int, int (*)(int));
/ports/trunk/editors/exvi/ex.1
0,0 → 1,2045
.\"
.\" 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.
.\"
.\" from ex.1 6.4.1 (2.11BSD) 1996/10/21
.\"
.\" Sccsid @(#)ex.1 1.44 (gritter) 12/1/04
.\"
.ie \n(.g==1 \{\
.ds lq \(lq
.ds rq \(rq
.\}
.el \{\
.ds lq ``
.ds rq ''
.\}
.TH EX 1 "12/1/04" "Ancient Unix Ports" "User Commands"
.SH NAME
ex, edit \- text editor
.SH SYNOPSIS
.HP
.ad l
\fBex\fR [\fB\-c\fI\ command\fR|\fB+\fIcommand\fR]
[\fB\-r\fR\ [\fIfilename\fR]] [\fB\-s\fR|\fB\-\fR]
[\fB\-t\fI\ tagstring\fR] [\fB\-w\fI\ size\fR]
[\fB\-lLRvV\fR] [\fIfile\fR ...]
.HP
.ad l
\fBedit\fR [\fB\-c\fI\ command\fR|\fB+\fIcommand\fR]
[\fB\-r\fR\ [\fIfilename\fR]] [\fB\-s\fR|\fB\-\fR]
[\fB\-t\fI\ tagstring\fR] [\fB\-w\fI\ size\fR]
[\fB\-lLRvV\fR] [\fIfile\fR ...]
.br
.ad b
.SH DESCRIPTION
.I Ex
is the root of a family of editors:
.I edit,
.I ex
and
.I vi.
.I Ex
is a superset of
.I ed,
with the most notable extension being a display editing facility.
Display based editing on
.SM CRT
terminals is the focus of
.IR vi .
.PP
For those who have not used
.I ed,
or for casual users, the editor
.I edit
may be convenient.
It avoids some of the complexities of
.I ex
used mostly by systems programmers and persons very familiar with
.I ed.
.PP
The following options are accepted:
.TP
\fB\-c\fP\fI\ command\fP or \fB+\fP\fIcommand\fP
Execute
.I command
when editing begins.
.TP
.B \-l
Start in a special mode useful for the
.I Lisp
programming language.
.TP
\fB\-r\fI\ [filename]\fR or \fB\-L\fR
When no argument is supplied with this option,
all files to be recovered are listed
and the editor exits immediately.
If a
.I filename
is specified,
the corresponding temporary file is opened in recovery mode.
.TP
.B \-R
Files are opened read-only when this option is given.
.TP
.BR \-s \ or\ \-
Script mode;
all feedback for interactive editing is disabled.
.SM EXINIT
and
.I .exrc
files are not processed.
.TP
.BI \-t \ tagstring
Read the
.I tags
file,
then choose the file and position specified by
.I tagstring
for editing.
.TP
.B \-v
Start in visual mode even if called as
.IR ex .
.TP
.B \-V
Echo command input to standard error,
unless it originates from a terminal.
.TP
.BI \-w \ size
Specify the size of the editing window for visual mode.
.\" from ex.rm 8.1 (Berkeley) 6/8/93
.SS "File manipulation"
.I Ex
is normally editing the contents of a single file,
whose name is recorded in the
.I current
file name.
.I Ex
performs all editing actions in a buffer
(actually a temporary file)
into which the text of the file is initially read.
Changes made to the buffer have no effect on the file being
edited unless and until the buffer contents are written out to the
file with a
.I write
command.
After the buffer contents are written,
the previous contents of the written file are no longer accessible.
When a file is edited,
its name becomes the current file name,
and its contents are read into the buffer.
.PP
The current file is almost always considered to be
.I edited.
This means that the contents of the buffer are logically
connected with the current file name,
so that writing the current buffer contents onto that file,
even if it exists,
is a reasonable action.
If the current file is not
.I edited
then
.I ex
will not normally write on it if it already exists.
.PP
For saving blocks of text while editing, and especially when editing
more than one file,
.I ex
has a group of named buffers.
These are similar to the normal buffer, except that only a limited number
of operations are available on them.
The buffers have names
.I a
through
.I z.
.SS "Exceptional Conditions"
.PP
When errors occur
.I ex
(optionally) rings the terminal bell and, in any case, prints an error
diagnostic. If the primary input is from a file, editor processing
will terminate. If an interrupt signal is received,
.I ex
prints \*(lqInterrupt\*(rq and returns to its command level. If the primary
input is a file, then
.I ex
will exit when this occurs.
.PP
If a hangup signal is received and the buffer has been modified since
it was last written out, or if the system crashes, either the editor
(in the first case) or the system (after it reboots in the second) will
attempt to preserve the buffer. The next time the user logs in he should be
able to recover the work he was doing, losing at most a few lines of
changes from the last point before the hangup or editor crash. To
recover a file one can use the
.B \-r
option. If one was editing the file
.I resume,
then he should change
to the directory where he were when the crash occurred, giving the command
.RS
.sp
\fBex \-r\fP\fI resume\fP
.sp
.RE
After checking that the retrieved file is indeed ok, he can
.I write
it over the previous contents of that file.
.PP
The user will normally get mail from the system telling him when a file has
been saved after a crash. The command
.RS
.sp
\fBex\fP \-\fBr\fP
.sp
.RE
will print a list of the files which have been saved for the user.
.\"(In the case of a hangup,
.\"the file will not appear in the list,
.\"although it can be recovered.)
.SS "Editing modes"
.PP
.I Ex
has five distinct modes. The primary mode is
.I command
mode. Commands are entered in command mode when a `:' prompt is
present, and are executed each time a complete line is sent. In
.I "text input"
mode
.I ex
gathers input lines and places them in the file. The
.I append,
.I insert,
and
.I change
commands use text input mode.
No prompt is printed when in text input mode.
This mode is left by typing a `.' alone at the beginning of a line, and
.I command
mode resumes.
.PP
The last three modes are
.I open
and
.I visual
modes, entered by the commands of the same name, and, within open and
visual modes
.I "text insertion"
mode.
.I Open
and
.I visual
modes allow local editing operations to be performed on the text in the
file. The
.I open
command displays one line at a time on any terminal while
.I visual
works on
.SM CRT
terminals with random positioning cursors, using the
screen as a (single) window for file editing changes.
These modes are described (only) in
.I "An Introduction to Display Editing with Vi."
.SS "Command structure"
.PP
Most command names are English words,
and initial prefixes of the words are acceptable abbreviations.
The ambiguity of abbreviations is resolved in favor of the more commonly
used commands.
.PP
Most commands accept prefix addresses specifying the lines in the file
upon which they are to have effect.
The forms of these addresses will be discussed below.
A number of commands also may take a trailing
.I count
specifying the number of lines to be involved in the command.
Thus the command \*(lq10p\*(rq will print the tenth line in the buffer while
\*(lqdelete 5\*(rq will delete five lines from the buffer,
starting with the current line.
.PP
Some commands take other information or parameters,
this information always being given after the command name.
.PP
A number of commands have two distinct variants.
The variant form of the command is invoked by placing an
`!' immediately after the command name.
Some of the default variants may be controlled by options;
in this case, the `!' serves to toggle the default.
.PP
The characters `#', `p' and `l' may be placed after many commands
(A `p' or `l' must be preceded by a blank or tab
except in the single special case `dp').
In this case, the command abbreviated by these characters
is executed after the command completes.
Since
.I ex
normally prints the new current line after each change, `p' is rarely necessary.
Any number of `+' or `\-' characters may also be given with these flags.
If they appear, the specified offset is applied to the current line
value before the printing command is executed.
.PP
It is possible to give editor commands which are ignored.
This is useful when making complex editor scripts
for which comments are desired.
The comment character is the double quote: ".
Any command line beginning with " is ignored.
Comments beginning with " may also be placed at the ends
of commands, except in cases where they could be confused as part
of text (shell escapes and the substitute and map commands).
.PP
More than one command may be placed on a line by separating each pair
of commands by a `|' character.
However the
.I global
commands,
comments,
and the shell escape `!'
must be the last command on a line, as they are not terminated by a `|'.
.SS "Command addressing"
.IP \fB.\fR 20
The current line.
Most commands leave the current line as the last line which they affect.
The default address for most commands is the current line,
thus `\fB.\fR' is rarely used alone as an address.
.IP \fIn\fR 20
The \fIn\fRth line in the editor's buffer, lines being numbered
sequentially from 1.
.IP \fB$\fR 20
The last line in the buffer.
.IP \fB%\fR 20
An abbreviation for \*(lq1,$\*(rq, the entire buffer.
.IP \fI+n\fR\ \fI\-n\fR 20
An offset relative to the current buffer line.
The forms `.+3' `+3' and `+++' are all equivalent;
if the current line is line 100 they all address line 103.
.IP \fB/\fIpat\fR\fB/\fR\ \fB?\fIpat\fR\fB?\fR 20
Scan forward and backward respectively for a line containing \fIpat\fR, a
regular expression (as defined below). The scans normally wrap around the end
of the buffer.
If all that is desired is to print the next line containing \fIpat\fR, then
the trailing \fB/\fR or \fB?\fR may be omitted.
If \fIpat\fP is omitted or explicitly empty, then the last
regular expression specified is located.
The forms \fB\e/\fP and \fB\e?\fP scan
using the last regular expression used in a scan; after a substitute
\fB//\fP and \fB??\fP would scan using the substitute's regular expression.
.IP \fB\(aa\(aa\fP\ \fB\(aa\fP\fIx\fP 20
Before each non-relative motion of the current line `\fB.\fP',
the previous current line is marked with a tag, subsequently referred to as
`\(aa\(aa'.
This makes it easy to refer or return to this previous context.
Marks may also be established by the
.I mark
command, using single lower case letters
.I x
and the marked lines referred to as
`\(aa\fIx\fR'.
.PP
Addresses to commands consist of a series of addressing primitives,
separated by `,' or `;'.
Such address lists are evaluated left-to-right.
When addresses are separated by `;' the current line `\fB.\fR'
is set to the value of the previous addressing expression
before the next address is interpreted.
If more addresses are given than the command requires,
then all but the last one or two are ignored.
If the command takes two addresses, the first addressed line must
precede the second in the buffer.
.PP
Null address specifications are permitted in a list of addresses,
the default in this case is the current line `.';
thus `,100' is equivalent to `\fB.\fR,100'.
It is an error to give a prefix address to a command which expects none.
.SS "Command descriptions"
.PP
The following form is a prototype for all
.I ex
commands:
.RS
.sp
\fIaddress\fR \fBcommand\fR \fI! parameters count flags\fR
.sp
.RE
All parts are optional; the degenerate case is the empty command which prints
the next line in the file. For sanity with use from within
.I visual
mode,
.I ex
ignores a \*(lq:\*(rq preceding any command.
.PP
In the following command descriptions, the
default addresses are shown in parentheses,
which are
.I not,
however,
part of the command.
.TP
\fBabbreviate\fR \fIword rhs\fP abbr: \fBab\fP
Add the named abbreviation to the current list.
When in input mode in visual, if
.I word
is typed as a complete word, it will be changed to
.I rhs .
.LP
( \fB.\fR ) \fBappend\fR abbr: \fBa\fR
.br
\fItext\fR
.br
\&\fB.\fR
.RS
Reads the input text and places it after the specified line.
After the command, `\fB.\fR'
addresses the last line input or the
specified line if no lines were input.
If address `0' is given,
text is placed at the beginning of the buffer.
.RE
.LP
\fBa!\fR
.br
\fItext\fR
.br
\&\fB.\fR
.RS
The variant flag to
.I append
toggles the setting for the
.I autoindent
option during the input of
.I text.
.RE
.TP
\fBargs\fR
The members of the argument list are printed, with the current argument
delimited by `[' and `]'.
.TP
\fBcd\fR \fIdirectory\fR
The
.I cd
command is a synonym for
.I chdir.
.LP
( \fB.\fP , \fB.\fP ) \fBchange\fP \fIcount\fP abbr: \fBc\fP
.br
\fItext\fP
.br
\&\fB.\fP
.RS
Replaces the specified lines with the input \fItext\fP.
The current line becomes the last line input;
if no lines were input it is left as for a
\fIdelete\fP.
.RE
.LP
\fBc!\fP
.br
\fItext\fP
.br
\&\fB.\fP
.RS
The variant toggles
.I autoindent
during the
.I change.
.RE
.TP
\fBchdir\fR \fIdirectory\fR
The specified \fIdirectory\fR becomes the current directory.
If no directory is specified, the current value of the
.I home
option is used as the target directory.
After a
.I chdir
the current file is not considered to have been
edited so that write restrictions on pre-existing files apply.
.TP
( \fB.\fP , \fB.\fP )\|\fBcopy\fP \fIaddr\fP \fIflags\fP abbr: \fBco\fP
A \fIcopy\fP
of the specified lines is placed after
.I addr,
which may be `0'.
The current line
`\fB.\fR'
addresses the last line of the copy.
The command
.I t
is a synonym for
.I copy.
.TP
( \fB.\fR , \fB.\fR )\|\fBdelete\fR \fIbuffer\fR \fIcount\fR \fIflags\fR abbr: \fBd\fR
Removes the specified lines from the buffer.
The line after the last line deleted becomes the current line;
if the lines deleted were originally at the end,
the new last line becomes the current line.
If a named
.I buffer
is specified by giving a letter,
then the specified lines are saved in that buffer,
or appended to it if an upper case letter is used.
.LP
\fBedit\fR \fIfile\fR abbr: \fBe\fR
.br
\fBex\fR \fIfile\fR
.RS
Used to begin an editing session on a new file.
The editor
first checks to see if the buffer has been modified since the last
.I write
command was issued.
If it has been,
a warning is issued and the
command is aborted.
The
command otherwise deletes the entire contents of the editor buffer,
makes the named file the current file and prints the new filename.
After insuring that this file is sensible
(i.e., that it is not a binary file such as a directory,
a block or character special file other than
.I /dev/tty,
a terminal,
or a binary or executable file),
the editor reads the file into its buffer.
.PP
If the read of the file completes without error,
the number of lines and characters read is typed.
Any null characters in the file are discarded.
If none of these errors occurred, the file is considered
.I edited.
If the last line of the input file is missing the trailing
newline character, it will be supplied and a complaint will be issued.
This command leaves the current line `\fB.\fR' at the last line read.
If executed from within
.I open
or
.I visual,
the current line is initially the first line of the file.
.RE
.TP
\fBe!\fR \fIfile\fR
The variant form suppresses the complaint about modifications having
been made and not written from the editor buffer, thus
discarding all changes which have been made before editing the new file.
.TP
\fBe\fR \fB+\fIn\fR \fIfile\fR
Causes the editor to begin at line
.I n
rather than at the last line;
\fIn\fR may also be an editor command containing no spaces,
e.g.: \*(lq+/pat\*(rq.
.TP
\fBfile\fR abbr: \fBf\fR
Prints the current file name,
whether it has been `[Modified]' since the last
.I write
command,
whether it is
.I "read only" ,
the current line,
the number of lines in the buffer,
and the percentage of the way through the buffer of the current line.
In the rare case that the current file is `[Not edited]' this is
noted also; in this case one has to use the form \fBw!\fR to write to
the file, since the editor is not sure that a \fBwrite\fR will not
destroy a file unrelated to the current contents of the buffer.
.TP
\fBfile\fR \fIfile\fR
The current file name is changed to
.I file
which is considered
`[Not edited]'.
.TP
( 1 , $ ) \fBglobal\fR /\fIpat\|\fR/ \fIcmds\fR abbr: \fBg\fR
First marks each line among those specified which matches
the given regular expression.
Then the given command list is executed with `\fB.\fR' initially
set to each marked line.
.IP
The command list consists of the remaining commands on the current
input line and may continue to multiple lines by ending all but the
last such line with a `\e'.
If
.I cmds
(and possibly the trailing \fB/\fR delimiter) is omitted, each line matching
.I pat
is printed.
.I Append,
.I insert,
and
.I change
commands and associated input are permitted;
the `\fB.\fR' terminating input may be omitted if it would be on the
last line of the command list.
.I Open
and
.I visual
commands are permitted in the command list and take input from the terminal.
.IP
The
.I global
command itself may not appear in
.I cmds.
The
.I undo
command is also not permitted there,
as
.I undo
instead can be used to reverse the entire
.I global
command.
The options
.I autoprint
and
.I autoindent
are inhibited during a
.I global,
(and possibly the trailing \fB/\fR delimiter) and the value of the
.I report
option is temporarily infinite,
in deference to a \fIreport\fR for the entire global.
Finally, the context mark `\'\'' is set to the value of
`.' before the global command begins and is not changed during a global
command,
except perhaps by an
.I open
or
.I visual
within the
.I global.
.TP
\fBg!\fR \fB/\fIpat\fB/\fR \fIcmds\fR abbr: \fBv\fR
The variant form of \fIglobal\fR runs \fIcmds\fR at each line not matching
\fIpat\fR.
.LP
( \fB.\fR )\|\fBinsert\fR abbr: \fBi\fR
.br
\fItext\fR
.br
\&\fB.\fR
.RS
Places the given text before the specified line.
The current line is left at the last line input;
if there were none input it is left at the line before the addressed line.
This command differs from
.I append
only in the placement of text.
.RE
.LP
\fBi!\fR
.br
\fItext\fR
.br
\&\fB.\fR
.RS
The variant toggles
.I autoindent
during the
.I insert.
.RE
.TP
( \fB.\fR , \fB.\fR+1 ) \fBjoin\fR \fIcount\fR \fIflags\fR abbr: \fBj\fR
Places the text from a specified range of lines
together on one line.
White space is adjusted at each junction to provide at least
one blank character, two if there was a `\fB.\fR' at the end of the line,
or none if the first following character is a `)'.
If there is already white space at the end of the line,
then the white space at the start of the next line will be discarded.
.TP
\fBj!\fR
The variant causes a simpler
.I join
with no white space processing; the characters in the lines are simply
concatenated.
.TP
( \fB.\fR ) \fBk\fR \fIx\fR
The
.I k
command is a synonym for
.I mark.
It does not require a blank or tab before the following letter.
.TP
( \fB.\fR , \fB.\fR ) \fBlist\fR \fIcount\fR \fIflags\fR
Prints the specified lines in a more unambiguous way:
tabs are printed as `^I'
and the end of each line is marked with a trailing `$'.
The current line is left at the last line printed.
.TP
\fBmap\fR[\fB!\fR] \fIlhs\fR \fIrhs\fR
The
.I map
command is used to define macros for use in
.I visual
command mode.
.I Lhs
should be a single character, or the sequence \*(lq#n\*(rq, for n a digit,
referring to function key \fIn\fR. When this character or function key
is typed in
.I visual
mode, it will be as though the corresponding \fIrhs\fR had been typed.
On terminals without function keys, the user can type \*(lq#n\*(rq.
If the `\fB!\fP' character follows the command name,
the mapping is interpreted in input mode.
See section 6.9 of the \*(lqIntroduction to Display Editing with Vi\*(rq
for more details.
.TP
( \fB.\fR ) \fBmark\fR \fIx\fR
Gives the specified line mark
.I x,
a single lower case letter.
The
.I x
must be preceded by a blank or a tab.
The addressing form `\'x' then addresses this line.
The current line is not affected by this command.
.TP
( \fB.\fR , \fB.\fR ) \fBmove\fR \fIaddr\fR abbr: \fBm\fR
The
.I move
command repositions the specified lines to be after
.I addr .
The first of the moved lines becomes the current line.
.TP
\fBnext\fR abbr: \fBn\fR
The next file from the command line argument list is edited.
.TP
\fBn!\fR
The variant suppresses warnings about the modifications to the buffer not
having been written out, discarding (irretrievably) any changes which may
have been made.
.LP
\fBn\fR \fIfilelist\fR
.br
\fBn\fR \fB+\fIcommand\fR \fIfilelist\fR
.RS
The specified
.I filelist
is expanded and the resulting list replaces the
current argument list;
the first file in the new list is then edited.
If
.I command
is given (it must contain no spaces), then it is executed after editing the first such file.
.RE
.TP
( \fB.\fR , \fB.\fR ) \fBnumber\fR \fIcount\fR \fIflags\fR abbr: \fB#\fR or \fBnu\fR
Prints each specified line preceded by its buffer line
number.
The current line is left at the last line printed.
.LP
( \fB.\fR ) \fBopen\fR \fIflags\fR abbr: \fBo\fR
.br
( \fB.\fR ) \fBopen\fR /\fIpat\|\fR/ \fIflags\fR
.RS
Enters intraline editing \fIopen\fR mode at each addressed line.
If
.I pat
is given,
then the cursor will be placed initially at the beginning of the
string matched by the pattern.
To exit this mode use Q.
See
.I "An Introduction to Display Editing with Vi"
for more details.
.RE
.TP
\fBpreserve\fR
The current editor buffer is saved as though the system had just crashed.
This command is for use only in emergencies when a
.I write
command has resulted in an error.
.TP
( \fB.\fR , \fB.\fR )\|\fBprint\fR \fIcount\fR abbr: \fBp\fR or \fBP\fR
Prints the specified lines
with non-printing characters printed as control characters `^\fIx\fR\|';
delete (octal 177) is represented as `^?'.
The current line is left at the last line printed.
.TP
( \fB.\fR )\|\fBput\fR \fIbuffer\fR abbr: \fBpu\fR
Puts back
previously
.I deleted
or
.I yanked
lines.
Normally used with
.I delete
to effect movement of lines,
or with
.I yank
to effect duplication of lines.
If no
.I buffer
is specified, then the last
.I deleted
or
.I yanked
text is restored.
But no modifying commands may intervene between the
.I delete
or
.I yank
and the
.I put,
nor may lines be moved between files without using a named buffer.
By using a named buffer, text may be restored that was saved there at any
previous time.
.TP
\fBquit\fR abbr: \fBq\fR
Causes
.I ex
to terminate.
No automatic write of the editor buffer to a file is performed.
However,
.I ex
issues a warning message if the file has changed
since the last
.I write
command was issued, and does not
.I quit.
\fIEx\fR
will also issue a diagnostic if there are more files in the argument
list.
.FE
Normally, the user will wish to save his changes, and he
should give a \fIwrite\fR command;
if he wishes to discard them, he should the \fBq!\fR command variant.
.TP
\fBq!\fR
Quits from the editor, discarding changes to the buffer without complaint.
.TP
( \fB.\fR ) \fBread\fR \fIfile\fR abbr: \fBr\fR
Places a copy of the text of the given file in the
editing buffer after the specified line.
If no
.I file
is given the current file name is used.
The current file name is not changed unless there is none in which
case
.I file
becomes the current name.
The sensibility restrictions for the
.I edit
command apply here also.
If the file buffer is empty and there is no current name then
.I ex
treats this as an
.I edit
command.
.IP
Address `0' is legal for this command and causes the file to be read at
the beginning of the buffer.
Statistics are given as for the
.I edit
command when the
.I read
successfully terminates.
After a
.I read
the current line is the last line read.
Within
.I open
and
.I visual
the current line is set to the first line read rather than the last.
.TP
( \fB.\fR ) \fBread\fR \fB!\fR\fIcommand\fR
Reads the output of the command
.I command
into the buffer after the specified line.
This is not a variant form of the command, rather a read
specifying a
.I command
rather than a
.I filename;
a blank or tab before the \fB!\fR is mandatory.
.TP
\fBrecover \fIfile\fR
Recovers
.I file
from the system save area.
Used after a accidental hangup of the phone
or a system crash or
.I preserve
command.
Except when
.I preserve
is used, the user will be notified by mail when a file is saved.
.TP
\fBrewind\fR abbr: \fBrew\fR
The argument list is rewound, and the first file in the list is edited.
.TP
\fBrew!\fR
Rewinds the argument list discarding any changes made to the current buffer.
.TP
\fBset\fR \fIparameter\fR
With no arguments, prints those options whose values have been
changed from their defaults;
with parameter
.I all
it prints all of the option values.
.IP
Giving an option name followed by a `?'
causes the current value of that option to be printed.
The `?' is unnecessary unless the option is Boolean valued.
Boolean options are given values either by the form
`set \fIoption\fR' to turn them on or
`set no\fIoption\fR' to turn them off;
string and numeric options are assigned via the form
`set \fIoption\fR=value'.
.IP
More than one parameter may be given to
.I set \|;
they are interpreted left-to-right.
.IP
A list of options can be found below.
.TP
\fBshell\fR abbr: \fBsh\fR
A new shell is created.
When it terminates, editing resumes.
.TP
\fBsource\fR \fIfile\fR abbr: \fBso\fR
Reads and executes commands from the specified file.
.I Source
commands may be nested.
.LP
.ad l
(\ \fB.\fR\ ,\ \fB.\fR\ )\ \fBsubstitute\fR\ /\fIpat\fR\|/\fIrepl\fR\|/\ \fIoptions\fR\ \fIcount\fR\ \fIflags\fR
.RS
abbr: \fBs\fR
.br
.ad b
On each specified line, the first instance of pattern
.I pat
is replaced by replacement pattern
.I repl.
If the
.I global
indicator option character `g'
appears, then all instances are substituted;
if the
.I confirm
indication character `c' appears,
then before each substitution the line to be substituted
is typed with the string to be substituted marked
with `^' characters.
By typing an `y' one can cause the substitution to be performed,
any other input causes no change to take place.
After a
.I substitute
the current line is the last line substituted.
.PP
Lines may be split by substituting
new-line characters into them.
The newline in
.I repl
must be escaped by preceding it with a `\e'.
Other metacharacters available in
.I pat
and
.I repl
are described below.
.RE
.TP
.B stop
Suspends the editor, returning control to the top level shell.
If
.I autowrite
is set and there are unsaved changes,
a write is done first unless the form
.B stop !
is used.
This commands is only available where supported by the teletype driver,
shell and operating system.
.TP
( \fB.\fR , \fB.\fR ) \fBsubstitute\fR \fIoptions\fR \fIcount\fR \fIflags\fR abbr: \fBs\fR
If
.I pat
and
.I repl
are omitted, then the last substitution is repeated.
This is a synonym for the
.B &
command.
.TP
( \fB.\fR , \fB.\fR ) \fBt\fR \fIaddr\fR \fIflags\fR
The
.I t
command is a synonym for
.I copy .
.TP
\fBta\fR \fItag\fR
The focus of editing switches to the location of
.I tag,
switching to a different line in the current file where it is defined,
or if necessary to another file.
.IP
The tags file is normally created by a program such as
.I ctags,
and consists of a number of lines with three fields separated by blanks
or tabs. The first field gives the name of the tag,
the second the name of the file where the tag resides, and the third
gives an addressing form which can be used by the editor to find the tag;
this field is usually a contextual scan using `/\fIpat\fR/' to be immune
to minor changes in the file. Such scans are always performed as if
.I nomagic
was set.
.IP
The tag names in the tags file must be sorted alphabetically.
.TP
\fBunabbreviate\fR \fIword\fP abbr: \fBuna\fP
Delete
.I word
from the list of abbreviations.
.TP
\fBundo\fR abbr: \fBu\fR
Reverses the changes made in the buffer by the last
buffer editing command.
Note that
.I global
commands are considered a single command for the purpose of
.I undo
(as are
.I open
and
.I visual.)
Also, the commands
.I write
and
.I edit
which interact with the
file system cannot be undone.
.I Undo
is its own inverse.
.IP
.I Undo
always marks the previous value of the current line `\fB.\fR'
as `\'\''.
After an
.I undo
the current line is the first line restored
or the line before the first line deleted if no lines were restored.
For commands with more global effect
such as
.I global
and
.I visual
the current line regains it's pre-command value after an
.I undo.
.TP
\fBunmap\fR[\fB!\fR] \fIlhs\fR
The macro expansion associated by
.I map
for
.I lhs
is removed.
.TP
( 1 , $ ) \fBv\fR /\fIpat\fR\|/ \fIcmds\fR
A synonym for the
.I global
command variant \fBg!\fR, running the specified \fIcmds\fR on each
line which does not match \fIpat\fR.
.TP
\fBversion\fR abbr: \fBve\fR
Prints the current version number of the editor
as well as the date the editor was last changed.
.TP
( \fB.\fR ) \fBvisual\fR \fItype\fR \fIcount\fR \fIflags\fR abbr: \fBvi\fR
Enters visual mode at the specified line.
.I Type
is optional and may be `\-' , `^' or `\fB.\fR'
as in the
.I z
command to specify the placement of the specified line on the screen.
By default, if
.I type
is omitted, the specified line is placed as the first on the screen.
A
.I count
specifies an initial window size; the default is the value of the option
.I window.
See the document
.I "An Introduction to Display Editing with Vi"
for more details.
To exit this mode, type Q.
.LP
\fBvisual\fP file
.br
\fBvisual\fP +\fIn\fP file
.RS
From visual mode,
this command is the same as edit.
.RE
.TP
( 1 , $ ) \fBwrite\fR \fIfile\fR abbr: \fBw\fR
Writes changes made back to \fIfile\fR, printing the number of lines and
characters written.
Normally \fIfile\fR is omitted and the text goes back where it came from.
If a \fIfile\fR is specified, then text will be written to that file.
If the file does not exist it is created.
The current file name is changed only if there is no current file
name; the current line is never changed.
.IP
If an error occurs while writing the current and
.I edited
file, the editor
considers that there has been \*(lqNo write since last change\*(rq
even if the buffer had not previously been modified.
.TP
( 1 , $ ) \fBwrite>>\fR \fIfile\fR abbr: \fBw>>\fR
Writes the buffer contents at the end of
an existing file.
.IP
.TP
\fBw!\fR \fIname\fR
Overrides the checking of the normal \fIwrite\fR command,
and will write to any file which the system permits.
.TP
( 1 , $ ) \fBw\fR \fB!\fR\fIcommand\fR
Writes the specified lines into
.I command.
Note the difference between \fBw!\fR which overrides checks and
\fBw\ \ !\fR which writes to a command.
.TP
\fBwq\fR \fIname\fR
Like a \fIwrite\fR and then a \fIquit\fR command.
.TP
\fBwq!\fR \fIname\fR
The variant overrides checking on the sensibility of the
.I write
command, as \fBw!\fR does.
.TP
\fBxit\fP \fIname\fR
If any changes have been made
and not written to any file,
writes the buffer out.
Then, in any case, quits.
.TP
( \fB.\fR , \fB.\fR )\|\fByank\fR \fIbuffer\fR \fIcount\fR abbr: \fBya\fR
Places the specified lines in the named
.I buffer,
for later retrieval via
.I put.
If no buffer name is specified, the lines go to a more volatile place;
see the \fIput\fR command description.
.TP
( \fB.+1\fR ) \fBz\fR \fIcount\fR
Print the next \fIcount\fR lines, default \fIwindow\fR.
.TP
( \fB.\fR ) \fBz\fR \fItype\fR \fIcount\fR
Prints a window of text with the specified line at the top.
If \fItype\fR is `\-' the line is placed at the bottom; a `\fB.\fR' causes
the line to be placed in the center.
A count gives the number of lines to be displayed rather than
double the number specified by the \fIscroll\fR option.
On a \s-1CRT\s0 the screen is cleared before display begins unless a
count which is less than the screen size is given.
The current line is left at the last line printed.
Forms `z=' and `z^' also exist; `z=' places the current line in the
center, surrounds it with lines of `\-' characters and leaves the current
line at this line. The form `z^' prints the window before `z\-'
would. The characters `+', `^' and `\-' may be repeated for cumulative
effect.
.TP
\fB!\fR \fIcommand\fR\fR
The remainder of the line after the `!' character is sent to a shell
to be executed.
Within the text of
.I command
the characters
`%' and `#' are expanded as in filenames and the character
`!' is replaced with the text of the previous command.
Thus, in particular,
`!!' repeats the last such shell escape.
If any such expansion is performed, the expanded line will be echoed.
The current line is unchanged by this command.
.IP
If there has been \*(lq[No\ write]\*(rq of the buffer contents since the last
change to the editing buffer, then a diagnostic will be printed
before the command is executed as a warning.
A single `!' is printed when the command completes.
.TP
( \fIaddr\fR , \fIaddr\fR ) \fB!\fR \fIcommand\fR\fR
Takes the specified address range and supplies it as
standard input to
.I command;
the resulting output then replaces the input lines.
.TP
( $ ) \fB=\fR
Prints the line number of the
addressed line.
The current line is unchanged.
.LP
( \fB.\fR , \fB.\fR ) \fB>\fR \fIcount\fR \fIflags\fR
.br
( \fB.\fR , \fB.\fR ) \fB<\fR \fIcount\fR \fIflags\fR
.RS
Perform intelligent shifting on the specified lines;
\fB<\fR shifts left and \fB>\fR shift right.
The quantity of shift is determined by the
.I shiftwidth
option and the repetition of the specification character.
Only white space (blanks and tabs) is shifted;
no non-white characters are discarded in a left-shift.
The current line becomes the last line which changed due to the
shifting.
.RE
.TP
\fB^D\fR
An end-of-file from a terminal input scrolls through the file.
The
.I scroll
option specifies the size of the scroll, normally a half screen of text.
.LP
( \fB.\fR+1 , \fB.\fR+1 )
.br
( \fB.\fR+1 , \fB.\fR+1 ) |
.RS
An address alone causes the addressed lines to be printed.
A blank line prints the next line in the file.
.RE
.TP
( \fB.\fR , \fB.\fR ) \fB&\fR \fIoptions\fR \fIcount\fR \fIflags\fR
Repeats the previous
.I substitute
command.
.TP
( \fB.\fR , \fB.\fR ) \fB\s+2~\s0\fR \fIoptions\fR \fIcount\fR \fIflags\fR
Replaces the previous regular expression with the previous
replacement pattern from a substitution.
.SS "Regular expressions"
.PP
A regular expression specifies a set of strings of characters.
A member of this set of strings is said to be
.I matched
by the regular expression.
.I Ex
remembers two previous regular expressions:
the previous regular expression used in a
.I substitute
command
and the previous regular expression used elsewhere
(referred to as the previous \fIscanning\fR regular expression.)
The previous regular expression
can always be referred to by a null \fIre\fR, e.g. `//' or `??'.
.PP
The following basic constructs are used to construct
.I magic
mode regular expressions.
.IP \fIchar\fR 15
An ordinary character matches itself.
The characters `\fB^\fR' at the beginning of a line,
`\fB$\fR' at the end of line,
`\fB*\fR' as any character other than the first,
`\fB.\fR', `\fB\e\fR', `\fB[\fR',
and `\s+2\fB~\fR\s0' are not ordinary characters and
must be escaped (preceded) by `\fB\e\fR' to be treated as such.
.IP \fB^\fR
At the beginning of a pattern
forces the match to succeed only at the beginning of a line.
.IP \fB$\fR
At the end of a regular expression forces the match to
succeed only at the end of the line.
.IP \&\fB.\fR
Matches any single character except
the new-line character.
.IP \fB\e<\fR
Forces the match
to occur only at the beginning of a \*(lqvariable\*(rq or \*(lqword\*(rq;
that is, either at the beginning of a line, or just before
a letter, digit, or underline and after a character not one of
these.
.IP \fB\e>\fR
Similar to `\e<', but matching the end of a \*(lqvariable\*(rq
or \*(lqword\*(rq, i.e. either the end of the line or before character
which is neither a letter, nor a digit, nor the underline character.
.IP \fB[\fIstring\fR\fB]\fR
Matches any (single) character in the class defined by
.I string.
Most characters in
.I string
define themselves.
.br
\ \ A pair of characters separated by `\fB\-\fR' in
.I string
defines the set of characters collating between the specified lower and upper
bounds, thus `[a\-z]' as a regular expression matches
any (single)
.SM ASCII
lower-case letter.
.br
\ \ If the sequence `\fB[:\fIclass\fB:]\fR' appears in
.IR string ,
where class is one of
.RB ` alnum ',
.RB ` alpha ',
.RB ` blank ',
.RB ` cntrl ',
.RB ` digit ',
.RB ` graph ',
.RB ` lower ',
.RB ` print ',
.RB ` punct ',
.RB ` space ',
.RB ` upper ',
.RB ` xdigit ',
or a locale-specific character class,
all characters that belong to the given class are matched.
Thus `[[:lower:]]' matches any lower-case letter,
possibly including characters beyond the scope of
.SM ASCII.
.br
\ \ If the first character of
.I string
is an `\fB^\fR' then the construct
matches those characters which it otherwise would not;
thus `[^a\-z]' matches anything but an
.SM ASCII
lower-case letter
(and of course a newline).
.br
\ \ Backslash `\e' is interpreted as an escape character.
To place a `\e' character in
.IR string ,
write it twice: `\e\e';
to place any of the characters
`^', `[', or `\-' in
.IR string ,
you escape them with a preceding `\e'.
.br
\ \ Characters also lose their special meaning by position:
`^' is an ordinary character unless immediately
following the initial `[',
`]' is an ordinary character if immediately
following the initial `[' (or `^', if present),
and `\-' is an ordinary character if placed immediately
behind `[' or `^', or before ']'.
.PP
The concatenation of two regular expressions matches the leftmost and
then longest string
which can be divided with the first piece matching the first regular
expression and the second piece matching the second.
.PP
A regular expression may be enclosed between the sequences
`\fB\e(\fR' and `\fB\e)\fR',
which matches whatever the enclosed expression matches.
.PP
Any of the (single character matching) regular expressions mentioned above
or a regular expression surrounded by `\e(' and '\e)'
may be followed by the character `\fB*\fR' to form a regular expression
which matches any number of adjacent occurrences (including 0) of characters
matched by the regular expression it follows.
.PP
A single character regular expression
or a regular expression surrounded by `\e(' and '\e)'
followed by `\fB\e{\fIm\fB,\fIn\fB\e}\fR'
matches a sequence of \fIm\fP through \fIn\fP occurences, inclusive,
of the single character expression.
The values of \fIm\fP and \fIn\fP
must be non-negative and smaller than 255.
The form `\fB\e{\fIm\fB\e}\fR' matches exactly \fIm\fP occurences,
`\fB\e{\fIm\fB,\e}\fR' matches at least \fIm\fP occurences.
.PP
The character `\s+2\fB~\fR\s0' may be used in a regular expression,
and matches the text which defined the replacement part
of the last
.I substitute
command.
.PP
The sequence `\fB\e\fIn\fR' matches the text that was matched by the
\fIn\fR-th regular subexpression enclosed between `\e(' and `\e)'
earlier in the expression.
.SS "Substitute replacement patterns"
.PP
The basic metacharacters for the replacement pattern are
`\fB&\fR', `\fB~\fR', and `\fB#\fR'; the first two of them are
given as `\fB\e&\fR' and `\fB\e~\fR' when
.I nomagic
is set.
Each instance of `\fB&\fR' is replaced by the characters
which the regular expression matched.
The metacharacter `\fB~\fR' stands, in the replacement pattern,
for the defining text of the previous replacement pattern.
If the entire replacement pattern is `\fB#\fR',
the defining text of the previous replacement pattern is used.
.PP
Other metasequences possible in the replacement pattern
are always introduced by the escaping character `\fB\e\fR'.
The sequence `\fB\e\fIn\fR' is replaced by the text matched
by the \fIn\fR-th regular subexpression enclosed between
`\e(' and `\e)'.
When nested, parenthesized subexpressions are present,
\fIn\fR is determined by counting occurrences of `\e(' starting from the left.
The sequences `\fB\eu\fR' and `\fB\el\fR'
cause the immediately following character in
the replacement to be converted to upper- or lower-case respectively
if this character is a letter.
The sequences `\fB\eU\fR' and `\fB\eL\fR'
turn such conversion on,
either until `\fB\eE\fR' or `\fB\ee\fR' is encountered,
or until the end of the replacement pattern.
.SS "Option descriptions"
.PP
.TP
\fBautoindent\fR, \fBai\fR default: noai
Can be used to ease the preparation of structured program text.
At the beginning of each
.I append ,
.I change
or
.I insert
command
or when a new line is
.I opened
or created by an
.I append ,
.I change ,
.I insert ,
or
.I substitute
operation within
.I open
or
.I visual
mode,
.I ex
looks at the line being appended after,
the first line changed
or the line inserted before and calculates the amount of white space
at the start of the line.
It then aligns the cursor at the level of indentation so determined.
.IP
If the user then types lines of text in,
they will continue to be justified at the displayed indenting level.
If more white space is typed at the beginning of a line,
the following line will start aligned with the first non-white character
of the previous line.
To back the cursor up to the preceding tab stop one can hit
\fB^D\fR.
The tab stops going backwards are defined at multiples of the
.I shiftwidth
option.
The user
.I cannot
backspace over the indent,
except by sending an end-of-file with a \fB^D\fR.
.IP
Specially processed in this mode is a line with no characters added
to it, which turns into a completely blank line (the white
space provided for the
.I autoindent
is discarded.)
Also specially processed in this mode are lines beginning with
an `^' and immediately followed by a \fB^D\fR.
This causes the input to be repositioned at the beginning of the line,
but retaining the previous indent for the next line.
Similarly, a `0' followed by a \fB^D\fR
repositions at the beginning but without
retaining the previous indent.
.IP
.I Autoindent
doesn't happen in
.I global
commands or when the input is not a terminal.
.TP
\fBautoprint\fR, \fBap\fR default: ap
Causes the current line to be printed after each
.I delete ,
.I copy ,
.I join ,
.I move ,
.I substitute ,
.I t ,
.I undo
or
shift command.
This has the same effect as supplying a trailing `p'
to each such command.
.I Autoprint
is suppressed in globals,
and only applies to the last of many commands on a line.
.TP
\fBautowrite\fR, \fBaw\fR default: noaw
Causes the contents of the buffer to be written to the current file
if the user has modified it and gives a
.I next,
.I rewind,