1 /*
2 * This code contains changes by
3 * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4 *
5 * Conditions 1, 2, and 4 and the no-warranty notice below apply
6 * to these changes.
7 *
8 *
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *
41 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * Redistributions of source code and documentation must retain the
47 * above copyright notice, this list of conditions and the following
48 * disclaimer.
49 * Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed or owned by Caldera
55 * International, Inc.
56 * Neither the name of Caldera International, Inc. nor the names of
57 * other contributors may be used to endorse or promote products
58 * derived from this software without specific prior written permission.
59 *
60 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72 */
73
74 #ifndef lint
75 #ifdef DOSCCS
76 static char sccsid[] = "@(#)ex_temp.c 1.24 (gritter) 11/24/04";
77 #endif
78 #endif
79
80 /* from ex_temp.c 7.5.1.1 (Berkeley) 8/12/86 */
81
82 #include "ex.h"
83 #include "ex_temp.h"
84 #include "ex_vis.h"
85 #include "ex_tty.h"
86 #include <sys/wait.h>
87 #include <time.h>
88
89 /*
90 * Editor temporary file routines.
91 * Very similar to those of ed, except uses 2 input buffers.
92 */
93 #define READ 0
94 #define WRITE 1
95
96 /*
97 * Maximum number of attempts to create temporary file.
98 */
99 #define ATTEMPTS 20
100
101 char *tfname;
102 char *rfname;
103 int havetmp;
104 int tfile = -1;
105 int rfile = -1;
106
107 void
fileinit(void)108 fileinit(void)
109 {
110 register char *p;
111 struct stat stbuf;
112 register int i, j;
113 pid_t mypid = getpid();
114 char *tfend;
115 int attempts = 0;
116
117 CLOBBGRD(attempts);
118 if (tline == INCRMT * (HBLKS+2))
119 return;
120 cleanup(0);
121 if (tfile != -1)
122 close(tfile);
123 tline = INCRMT * (HBLKS+2);
124 blocks[0] = HBLKS;
125 blocks[1] = HBLKS+1;
126 blocks[2] = -1;
127 dirtcnt = 0;
128 iblock = -1;
129 iblock2 = -1;
130 oblock = -1;
131 tfname = realloc(tfname, strlen(svalue(DIRECTORY)) + 14);
132 CP(tfname, svalue(DIRECTORY));
133 if (stat(tfname, &stbuf)) {
134 dumbness:
135 if (setexit() == 0)
136 filioerr(tfname);
137 else
138 putNFL();
139 cleanup(1);
140 exitex(1);
141 }
142 if ((stbuf.st_mode & S_IFMT) != S_IFDIR) {
143 errno = ENOTDIR;
144 goto dumbness;
145 }
146 ichanged = 0;
147 ichang2 = 0;
148 #ifdef notdef /* GR */
149 ignore(strcat(tfname, "/ExXXXXX"));
150 for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10)
151 *--p = j % 10 | '0';
152 tfile = creat(tfname, 0600);
153 #else
154 ignore(strcat(tfname, "/ExXXXXXXXXXX"));
155 tfend = strend(tfname);
156 do {
157 for (p = tfend, i = 10, j = mypid + attempts;
158 i > 0; i--, j /= 10)
159 *--p = j % 10 | '0';
160 tfile = open(tfname, O_CREAT|O_EXCL|O_RDWR
161 #ifdef O_NOFOLLOW
162 |O_NOFOLLOW
163 #endif /* O_NOFOLLOW */
164 , 0600);
165 } while (tfile < 0 && attempts++ < ATTEMPTS);
166 #endif /* !notdef */
167 if (tfile < 0)
168 goto dumbness;
169 #ifdef INCORB
170 {
171 extern bloc stilinc; /* see below */
172 stilinc = 0;
173 }
174 #endif
175 havetmp = 1;
176 /* brk((char *)fendcore); */
177 }
178
179 void
cleanup(bool all)180 cleanup(bool all)
181 {
182 if (all) {
183 putpad(TE);
184 flush();
185 }
186 if (havetmp)
187 unlink(tfname);
188 havetmp = 0;
189 if (all && rfile >= 0) {
190 unlink(rfname);
191 close(rfile);
192 rfile = -1;
193 }
194 }
195
196 void
getline(line tl)197 getline(line tl)
198 {
199 register char *bp, *lp;
200 register bbloc nl;
201
202 lp = linebuf;
203 bp = getblock(tl, READ);
204 nl = nleft;
205 tl &= ~OFFMSK;
206 while (*lp++ = *bp++)
207 if (--nl == 0) {
208 bp = getblock(tl += INCRMT, READ);
209 nl = nleft;
210 }
211 }
212
213 line
putline(void)214 putline(void)
215 {
216 register char *bp, *lp;
217 register bbloc nl;
218 line tl;
219
220 dirtcnt++;
221 lp = linebuf;
222 change();
223 tl = tline;
224 bp = getblock(tl, WRITE);
225 nl = nleft;
226 tl &= ~OFFMSK;
227 while (*bp = *lp++) {
228 if (*bp++ == '\n') {
229 *--bp = 0;
230 linebp = lp;
231 break;
232 }
233 if (--nl == 0) {
234 bp = getblock(tl += INCRMT, WRITE);
235 nl = nleft;
236 }
237 }
238 tl = tline;
239 tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776;
240 return (tl);
241 }
242
243 char *
getblock(line atl,int iof)244 getblock(line atl, int iof)
245 {
246 register bbloc bno, off;
247
248 bno = (atl >> OFFBTS) & BLKMSK;
249 off = (atl << SHFT) & LBTMSK;
250 if (bno >= NMBLKS)
251 error(catgets(catd, 1, 183, " Tmp file too large"));
252 nleft = BUFSIZ - off;
253 if (bno == iblock) {
254 ichanged |= iof;
255 hitin2 = 0;
256 return (ibuff + off);
257 }
258 if (bno == iblock2) {
259 ichang2 |= iof;
260 hitin2 = 1;
261 return (ibuff2 + off);
262 }
263 if (bno == oblock)
264 return (obuff + off);
265 if (iof == READ) {
266 if (hitin2 == 0) {
267 if (ichang2) {
268 blkio(iblock2, ibuff2, (ssize_t(*)())write);
269 }
270 ichang2 = 0;
271 iblock2 = bno;
272 blkio(bno, ibuff2, (ssize_t(*)())read);
273 hitin2 = 1;
274 return (ibuff2 + off);
275 }
276 hitin2 = 0;
277 if (ichanged) {
278 blkio(iblock, ibuff, (ssize_t(*)())write);
279 }
280 ichanged = 0;
281 iblock = bno;
282 blkio(bno, ibuff, (ssize_t(*)())read);
283 return (ibuff + off);
284 }
285 if (oblock >= 0) {
286 blkio(oblock, obuff, (ssize_t(*)())write);
287 }
288 oblock = bno;
289 return (obuff + off);
290 }
291
292 #ifdef INCORB
293 char incorb[INCORB+1][BUFSIZ];
294 #define pagrnd(a) ((char *)(((size_t)a)&~(BUFSIZ-1)))
295 bloc stilinc; /* up to here not written yet */
296 #endif
297
298 void
blkio(bloc b,char * buf,ssize_t (* iofcn)(int,void *,size_t))299 blkio(bloc b, char *buf, ssize_t (*iofcn)(int, void *, size_t))
300 {
301
302 #ifdef INCORB
303 if (b < INCORB) {
304 if (iofcn == (ssize_t(*)())read) {
305 copy(buf, pagrnd(incorb[b+1]), (size_t) BUFSIZ);
306 return;
307 }
308 copy(pagrnd(incorb[b+1]), buf, (size_t) BUFSIZ);
309 if (laste) {
310 if (b >= stilinc)
311 stilinc = b + 1;
312 return;
313 }
314 } else if (stilinc)
315 tflush();
316 #endif
317 lseek(tfile, (off_t) ((b & BLKMSK) * BUFSIZ), SEEK_SET);
318 if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
319 filioerr(tfname);
320 }
321
322 #ifdef INCORB
323 void
tlaste(void)324 tlaste(void)
325 {
326
327 if (stilinc)
328 dirtcnt = 0;
329 }
330
331 void
tflush(void)332 tflush(void)
333 {
334 bbloc i = stilinc;
335
336 stilinc = 0;
337 lseek(tfile, (off_t) 0, SEEK_SET);
338 if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ))
339 filioerr(tfname);
340 }
341 #endif
342
343 /*
344 * Synchronize the state of the temporary file in case
345 * a crash occurs.
346 */
347 void
synctmp(void)348 synctmp(void)
349 {
350 register bbloc cnt;
351 register line *a;
352 register bloc *bp, *up;
353
354 #ifdef INCORB
355 if (stilinc)
356 return;
357 #endif
358 if (dol == zero)
359 return;
360 if (ichanged)
361 blkio(iblock, ibuff, (ssize_t(*)())write);
362 ichanged = 0;
363 if (ichang2)
364 blkio(iblock2, ibuff2, (ssize_t(*)())write);
365 ichang2 = 0;
366 if (oblock != -1)
367 blkio(oblock, obuff, (ssize_t(*)())write);
368 time(&H.Time);
369 uid = getuid();
370 *zero = (line) H.Time;
371 up = blocks + LBLKS;
372 for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) {
373 if (bp >= up)
374 error(catgets(catd, 1, 184, " Tmp file too large"));
375 if (*bp < 0) {
376 tline = (tline + OFFMSK) &~ OFFMSK;
377 *bp = ((tline >> OFFBTS) & BLKMSK);
378 if (*bp > NMBLKS)
379 error(catgets(catd, 1, 185,
380 " Tmp file too large"));
381 tline += INCRMT;
382 oblock = *bp + 1;
383 bp[1] = -1;
384 }
385 lseek(tfile, (off_t) ((*bp & BLKMSK) * BUFSIZ), SEEK_SET);
386 cnt = ((dol - a) + 2) * sizeof (line);
387 if (cnt > BUFSIZ)
388 cnt = BUFSIZ;
389 if (write(tfile, (char *) a, cnt) != cnt) {
390 oops:
391 *zero = 0;
392 filioerr(tfname);
393 }
394 *zero = 0;
395 }
396 flines = lineDOL();
397 lseek(tfile, (off_t) 0, SEEK_SET);
398 if (write(tfile, (char *) &H, sizeof H) != sizeof H)
399 goto oops;
400 #ifdef notdef
401 /*
402 * This will insure that exrecover gets as much
403 * back after a crash as is absolutely possible,
404 * but can result in pregnant pauses between commands
405 * when the TSYNC call is made, so...
406 */
407 fsync(tfile);
408 #endif
409 }
410
411 void
TSYNC(void)412 TSYNC(void)
413 {
414
415 if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */
416 #ifdef INCORB
417 if (stilinc)
418 tflush();
419 #endif
420 dirtcnt = 0;
421 synctmp();
422 }
423 }
424
425 /*
426 * Named buffer routines.
427 * These are implemented differently than the main buffer.
428 * Each named buffer has a chain of blocks in the register file.
429 * Each block contains roughly 508 chars of text,
430 * and a previous and next block number. We also have information
431 * about which blocks came from deletes of multiple partial lines,
432 * e.g. deleting a sentence or a LISP object.
433 *
434 * We maintain a free map for the temp file. To free the blocks
435 * in a register we must read the blocks to find how they are chained
436 * together.
437 *
438 * BUG: The default savind of deleted lines in numbered
439 * buffers may be rather inefficient; it hasn't been profiled.
440 */
441 struct strreg {
442 short rg_flags;
443 short rg_nleft;
444 short rg_first;
445 short rg_last;
446 } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp;
447
448 struct rbuf {
449 short rb_prev;
450 short rb_next;
451 char rb_text[BUFSIZ - 2 * sizeof (short)];
452 } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf;
453 #ifdef VMUNIX
454 #ifdef LARGEF
455 short rused[4096];
456 #else /* !LARGEF */
457 short rused[256];
458 #endif /* !LARGEF */
459 #else /* !VMUNIX */
460 short rused[32];
461 #endif /* !VMUNIX */
462 short rnleft;
463 short rblock;
464 short rnext;
465 char *rbufcp;
466
467 void
regio(short b,ssize_t (* iofcn)(int,void *,size_t))468 regio(short b, ssize_t (*iofcn)(int, void *, size_t))
469 {
470 register char *p;
471 char *rfend;
472 int attempts = 0;
473 register int i, j;
474 pid_t mypid = getpid();
475
476 if (rfile == -1) {
477 rfname = realloc(rfname, strlen(svalue(DIRECTORY)) + 14);
478 CP(rfname, tfname);
479 rfend = strend(rfname);
480 #ifdef notdef /* GR */
481 *(rfend - 7) = 'R';
482 #else
483 *(rfend - 12) = 'R';
484 #endif
485 do {
486 for (p = rfend, i = 10, j = mypid + attempts;
487 i > 0; i--, j /= 10)
488 *--p = j % 10 | '0';
489 rfile = open(rfname, O_CREAT|O_EXCL|O_RDWR
490 #ifdef O_NOFOLLOW
491 |O_NOFOLLOW
492 #endif /* O_NOFOLLOW */
493 , 0600);
494 } while (rfile < 0 && attempts++ < ATTEMPTS);
495 if (rfile < 0)
496 oops:
497 filioerr(rfname);
498 }
499 lseek(rfile, (off_t) ((b & BLKMSK) * BUFSIZ), SEEK_SET);
500 if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ)
501 goto oops;
502 rblock = b;
503 }
504
505 int
REGblk(void)506 REGblk(void)
507 {
508 register int i, j, m;
509
510 for (i = 0; i < sizeof rused / sizeof rused[0]; i++) {
511 m = (rused[i] ^ 0177777) & 0177777;
512 if (i == 0)
513 m &= ~1;
514 if (m != 0) {
515 j = 0;
516 while ((m & 1) == 0)
517 j++, m >>= 1;
518 rused[i] |= (1 << j);
519 #ifdef RDEBUG
520 printf("allocating block %d\n", i * 16 + j);
521 #endif
522 return (i * 16 + j);
523 }
524 }
525 error(catgets(catd, 1, 186, "Out of register space (ugh)"));
526 /*NOTREACHED*/
527 return 0;
528 }
529
530 struct strreg *
mapreg(register int c)531 mapreg(register int c)
532 {
533
534 if (isupper(c))
535 c = tolower(c);
536 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
537 }
538
539 void
KILLreg(register int c)540 KILLreg(register int c)
541 {
542 register struct strreg *sp;
543
544 rbuf = &KILLrbuf;
545 sp = mapreg(c);
546 rblock = sp->rg_first;
547 sp->rg_first = sp->rg_last = 0;
548 sp->rg_flags = sp->rg_nleft = 0;
549 while (rblock != 0) {
550 #ifdef RDEBUG
551 printf("freeing block %d\n", rblock);
552 #endif
553 rused[rblock / 16] &= ~(1 << (rblock % 16));
554 regio(rblock, (ssize_t (*)(int, void *, size_t))shread);
555 rblock = rbuf->rb_next;
556 }
557 }
558
559 ssize_t
shread(void)560 shread(void)
561 {
562 struct front { short a; short b; };
563
564 if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front))
565 return (sizeof (struct rbuf));
566 return (0);
567 }
568
569 int getREG();
570
571 void
putreg(int c)572 putreg(int c)
573 {
574 register line *odot = dot;
575 register line *odol = dol;
576 register int cnt;
577
578 deletenone();
579 appendnone();
580 rbuf = &putrbuf;
581 rnleft = 0;
582 rblock = 0;
583 rnext = mapreg(c)->rg_first;
584 if (rnext == 0) {
585 if (inopen) {
586 splitw++;
587 vclean();
588 vgoto(WECHO, 0);
589 }
590 vreg = -1;
591 error(catgets(catd, 1, 187, "Nothing in register %c"), c);
592 }
593 if (inopen && partreg(c)) {
594 if (!FIXUNDO) {
595 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
596 error(catgets(catd, 1, 188,
597 "Can't put partial line inside macro"));
598 }
599 squish();
600 addr1 = addr2 = dol;
601 }
602 cnt = append(getREG, addr2);
603 if (inopen && partreg(c)) {
604 unddol = dol;
605 dol = odol;
606 dot = odot;
607 pragged(0);
608 }
609 killcnt(cnt);
610 notecnt = cnt;
611 }
612
613 int
partreg(int c)614 partreg(int c)
615 {
616
617 return (mapreg(c)->rg_flags);
618 }
619
620 void
notpart(register int c)621 notpart(register int c)
622 {
623
624 if (c)
625 mapreg(c)->rg_flags = 0;
626 }
627
628 int
getREG(void)629 getREG(void)
630 {
631 register char *lp = linebuf;
632 register int c;
633
634 for (;;) {
635 if (rnleft == 0) {
636 if (rnext == 0)
637 return (EOF);
638 regio(rnext, read);
639 rnext = rbuf->rb_next;
640 rbufcp = rbuf->rb_text;
641 rnleft = sizeof rbuf->rb_text;
642 }
643 c = *rbufcp;
644 if (c == 0)
645 return (EOF);
646 rbufcp++, --rnleft;
647 if (c == '\n') {
648 *lp++ = 0;
649 return (0);
650 }
651 *lp++ = c;
652 }
653 }
654
655 void
YANKreg(register int c)656 YANKreg(register int c)
657 {
658 register line *addr;
659 register struct strreg *sp;
660 char savelb[LBSIZE];
661
662 if (isdigit(c))
663 kshift();
664 if (islower(c))
665 KILLreg(c);
666 strp = sp = mapreg(c);
667 sp->rg_flags = inopen && cursor && wcursor;
668 rbuf = &YANKrbuf;
669 if (sp->rg_last) {
670 regio(sp->rg_last, read);
671 rnleft = sp->rg_nleft;
672 rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
673 } else {
674 rblock = 0;
675 rnleft = 0;
676 }
677 CP(savelb,linebuf);
678 for (addr = addr1; addr <= addr2; addr++) {
679 getline(*addr);
680 if (sp->rg_flags) {
681 if (addr == addr2)
682 *wcursor = 0;
683 if (addr == addr1)
684 strcpy(linebuf, cursor);
685 }
686 YANKline();
687 }
688 rbflush();
689 killed();
690 CP(linebuf,savelb);
691 }
692
693 void
kshift(void)694 kshift(void)
695 {
696 register int i;
697
698 KILLreg('9');
699 for (i = '8'; i >= '0'; i--)
700 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
701 }
702
703 void
YANKline(void)704 YANKline(void)
705 {
706 register char *lp = linebuf;
707 register struct rbuf *rp = rbuf;
708 register int c;
709
710 do {
711 c = *lp++;
712 if (c == 0)
713 c = '\n';
714 if (rnleft == 0) {
715 rp->rb_next = REGblk();
716 rbflush();
717 rblock = rp->rb_next;
718 rp->rb_next = 0;
719 rp->rb_prev = rblock;
720 rnleft = sizeof rp->rb_text;
721 rbufcp = rp->rb_text;
722 }
723 *rbufcp++ = c;
724 --rnleft;
725 } while (c != '\n');
726 if (rnleft)
727 *rbufcp = 0;
728 }
729
730 void
rbflush(void)731 rbflush(void)
732 {
733 register struct strreg *sp = strp;
734
735 if (rblock == 0)
736 return;
737 regio(rblock, (ssize_t (*)(int, void *, size_t))write);
738 if (sp->rg_first == 0)
739 sp->rg_first = rblock;
740 sp->rg_last = rblock;
741 sp->rg_nleft = rnleft;
742 }
743
744 /* Register c to char buffer buf of size buflen */
745 void
regbuf(char c,char * buf,int buflen)746 regbuf(char c, char *buf, int buflen)
747 {
748 register char *p, *lp;
749
750 rbuf = ®rbuf;
751 rnleft = 0;
752 rblock = 0;
753 rnext = mapreg(c)->rg_first;
754 if (rnext==0) {
755 *buf = 0;
756 error(catgets(catd, 1, 189, "Nothing in register %c"),c);
757 }
758 p = buf;
759 while (getREG()==0) {
760 for (lp=linebuf; *lp;) {
761 if (p >= &buf[buflen])
762 error(catgets(catd, 1, 190,
763 "Register too long@to fit in memory"));
764 *p++ = *lp++;
765 }
766 *p++ = '\n';
767 }
768 if (partreg(c)) p--;
769 *p = '\0';
770 getDOT();
771 }
772