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 = &regrbuf;
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