summaryrefslogtreecommitdiff
path: root/ex_temp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ex_temp.c')
-rw-r--r--ex_temp.c771
1 files changed, 771 insertions, 0 deletions
diff --git a/ex_temp.c b/ex_temp.c
new file mode 100644
index 0000000..a1127f9
--- /dev/null
+++ b/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();
+}