mirror of https://github.com/tildeclub/ex-vi.git
772 lines
16 KiB
C
772 lines
16 KiB
C
/*
|
|
* 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 = ®rbuf;
|
|
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();
|
|
}
|