xref: /titanic_44/usr/src/cmd/vi/port/ex_temp.c (revision bd335c6465ddbafe543900df4b03247bfa288eff)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /* Copyright (c) 1981 Regents of the University of California */
27 
28 /*
29  * Copyright 1999-2003 Sun Microsystems, Inc.  All rights reserved.
30  * Use is subject to license terms.
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 #include "ex.h"
35 #include "ex_temp.h"
36 #include "ex_vis.h"
37 #include "ex_tty.h"
38 
39 /*
40  * Editor temporary file routines.
41  * Very similar to those of ed, except uses 2 input buffers.
42  */
43 #define	READ	0
44 #define	WRITE	1
45 
46 unsigned char	tfname[PATH_MAX+1];
47 static unsigned char	rfname[PATH_MAX+1];
48 static unsigned char	tempname[PATH_MAX+1];
49 int	havetmp;
50 short	tfile = -1;
51 static short	rfile = -1;
52 
53 fileinit()
54 {
55 	register unsigned char *p;
56 	register pid_t j;
57 	register int i;
58 	struct stat64 stbuf;
59 
60 	if (tline == INCRMT * (HBLKS+2))
61 		return;
62 	cleanup(0);
63 	if (tfile != -1)
64 		close(tfile);
65 	tline = INCRMT * (HBLKS+2);
66 	blocks[0] = HBLKS;
67 	blocks[1] = HBLKS+1;
68 	blocks[2] = -1;
69 	dirtcnt = 0;
70 	iblock = -1;
71 	iblock2 = -1;
72 	oblock = -1;
73 	if (strlen(svalue(vi_DIRECTORY)) > (PATH_MAX -13))
74 		error(gettext("User set directory too long"));
75 	CP(tfname, svalue(vi_DIRECTORY));
76 	if (stat64((char *)tfname, &stbuf)) {
77 dumbness:
78 		if (setexit() == 0)
79 			filioerr(tfname);
80 		else
81 			putNFL();
82 		cleanup(1);
83 		exit(++errcnt);
84 	}
85 	if (!ISDIR(stbuf)) {
86 		errno = ENOTDIR;
87 		goto dumbness;
88 	}
89 	CP(tempname, tfname);
90 	ichanged = 0;
91 	ichang2 = 0;
92 	(void) strcat(tfname, "/ExXXXXXX");
93 	if ((tfile = mkstemp((char *)tfname)) < 0)
94 		goto dumbness;
95 #ifdef VMUNIX
96 	{
97 		extern stilinc;		/* see below */
98 		stilinc = 0;
99 	}
100 #endif
101 	havetmp = 1;
102 /* 	brk((unsigned char *)fendcore); */
103 }
104 
105 cleanup(all)
106 	bool all;
107 {
108 	pid_t pgrp;
109 	if (all) {
110 		if (kflag)
111 			crypt_close(perm);
112 		if (xtflag)
113 			crypt_close(tperm);
114 		putpad(exit_ca_mode);
115 		flush();
116 		if (ioctl(2, TIOCGPGRP, &pgrp) == 0) {
117 			if (pgrp == getpgid(0)) {
118 #ifdef XPG4
119 				if (envlines != -1 || envcolumns != -1) {
120 					struct winsize jwin;
121 					jwin.ws_row = oldlines;
122 					jwin.ws_col = oldcolumns;
123 					ioctl(0, TIOCSWINSZ, &jwin);
124 				}
125 #endif /* XPG4 */
126 				resetterm();
127 				normtty--;
128 			}
129 		} else {
130 #ifdef XPG4
131 			if (envlines != -1 || envcolumns != -1) {
132 				struct winsize jwin;
133 				jwin.ws_row = oldlines;
134 				jwin.ws_col = oldcolumns;
135 				ioctl(0, TIOCSWINSZ, &jwin);
136 			}
137 #endif /* XPG4 */
138 			resetterm();
139 			normtty--;
140 		}
141 	}
142 	if (havetmp)
143 		unlink(tfname);
144 	havetmp = 0;
145 	if (all && rfile >= 0) {
146 		unlink(rfname);
147 		close(rfile);
148 		rfile = -1;
149 	}
150 	if (all == 1)
151 		exit(errcnt);
152 }
153 
154 getline(tl)
155 	line tl;
156 {
157 	register unsigned char *bp, *lp;
158 	register int nl;
159 
160 	lp = linebuf;
161 	bp = getblock(tl, READ);
162 	nl = nleft;
163 	tl &= ~OFFMSK;
164 	while (*lp++ = *bp++)
165 		if (--nl == 0) {
166 			bp = getblock(tl += INCRMT, READ);
167 			nl = nleft;
168 		}
169 }
170 
171 putline()
172 {
173 	register unsigned char *bp, *lp;
174 	register int nl;
175 	line tl;
176 
177 	dirtcnt++;
178 	lp = linebuf;
179 	change();
180 	tl = tline;
181 	bp = getblock(tl, WRITE);
182 	nl = nleft;
183 	tl &= ~OFFMSK;
184 	while (*bp = *lp++) {
185 		if (*bp++ == '\n') {
186 			*--bp = 0;
187 			linebp = lp;
188 			break;
189 		}
190 		if (--nl == 0) {
191 			bp = getblock(tl += INCRMT, WRITE);
192 			nl = nleft;
193 		}
194 	}
195 	tl = tline;
196 	tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776;
197 	return (tl);
198 }
199 
200 int	read();
201 int	write();
202 
203 unsigned char *
204 getblock(atl, iof)
205 	line atl;
206 	int iof;
207 {
208 	register int bno, off;
209 	register unsigned char *p1, *p2;
210 	register int n;
211 	line *tmpptr;
212 
213 	bno = (atl >> OFFBTS) & BLKMSK;
214 	off = (atl << SHFT) & LBTMSK;
215 	if (bno >= NMBLKS) {
216 		/*
217 		 * When we overflow tmpfile buffers,
218 		 * throw away line which could not be
219 		 * put into buffer.
220 		 */
221 		for (tmpptr = dot; tmpptr < unddol; tmpptr++)
222 			*tmpptr = *(tmpptr+1);
223 		if (dot == dol)
224 			dot--;
225 		dol--;
226 		unddol--;
227 		error(gettext(" Tmp file too large"));
228 	}
229 	nleft = BUFSIZE - off;
230 	if (bno == iblock) {
231 		ichanged |= iof;
232 		hitin2 = 0;
233 		return (ibuff + off);
234 	}
235 	if (bno == iblock2) {
236 		ichang2 |= iof;
237 		hitin2 = 1;
238 		return (ibuff2 + off);
239 	}
240 	if (bno == oblock)
241 		return (obuff + off);
242 	if (iof == READ) {
243 		if (hitin2 == 0) {
244 			if (ichang2) {
245 				if (xtflag)
246 					if (run_crypt(0L, ibuff2,
247 							CRSIZE, tperm) == -1)
248 						filioerr(tfname);
249 				blkio(iblock2, ibuff2, write);
250 			}
251 			ichang2 = 0;
252 			iblock2 = bno;
253 			blkio(bno, ibuff2, read);
254 			if (xtflag)
255 				if (run_crypt(0L, ibuff2, CRSIZE, tperm) == -1)
256 					filioerr(tfname);
257 			hitin2 = 1;
258 			return (ibuff2 + off);
259 		}
260 		hitin2 = 0;
261 		if (ichanged) {
262 			if (xtflag)
263 				if (run_crypt(0L, ibuff, CRSIZE, tperm) == -1)
264 					filioerr(tfname);
265 			blkio(iblock, ibuff, write);
266 		}
267 		ichanged = 0;
268 		iblock = bno;
269 		blkio(bno, ibuff, read);
270 		if (xtflag)
271 			if (run_crypt(0L, ibuff, CRSIZE, tperm) == -1)
272 				filioerr(tfname);
273 		return (ibuff + off);
274 	}
275 	if (oblock >= 0) {
276 		if (xtflag) {
277 			/*
278 			 * Encrypt block before writing, so some devious
279 			 * person can't look at temp file while editing.
280 			 */
281 			p1 = obuff;
282 			p2 = crbuf;
283 			n = CRSIZE;
284 			while (n--)
285 				*p2++ = *p1++;
286 			if (run_crypt(0L, crbuf, CRSIZE, tperm) == -1)
287 				filioerr(tfname);
288 			blkio(oblock, crbuf, write);
289 		} else
290 			blkio(oblock, obuff, write);
291 	}
292 	oblock = bno;
293 	return (obuff + off);
294 }
295 
296 #ifdef	VMUNIX
297 #define	INCORB	64
298 unsigned char	incorb[INCORB+1][BUFSIZE];
299 #define	pagrnd(a)	((unsigned char *)(((int)a)&~(BUFSIZE-1)))
300 int	stilinc;	/* up to here not written yet */
301 #endif
302 
303 blkio(b, buf, iofcn)
304 	short b;
305 	unsigned char *buf;
306 	int (*iofcn)();
307 {
308 
309 #ifdef VMUNIX
310 	if (b < INCORB) {
311 		if (iofcn == read) {
312 			bcopy(pagrnd(incorb[b+1]), buf, BUFSIZE);
313 			return;
314 		}
315 		bcopy(buf, pagrnd(incorb[b+1]), BUFSIZE);
316 		if (laste) {
317 			if (b >= stilinc)
318 				stilinc = b + 1;
319 			return;
320 		}
321 	} else if (stilinc)
322 		tflush();
323 #endif
324 	lseek(tfile, (long)(unsigned)b * BUFSIZE, 0);
325 	if ((*iofcn)(tfile, buf, BUFSIZE) != BUFSIZE)
326 		filioerr(tfname);
327 }
328 
329 #ifdef VMUNIX
330 tlaste()
331 {
332 
333 	if (stilinc)
334 		dirtcnt = 0;
335 }
336 
337 tflush()
338 {
339 	int i = stilinc;
340 
341 	stilinc = 0;
342 	lseek(tfile, (long)0, 0);
343 	if (write(tfile, pagrnd(incorb[1]), i * BUFSIZE) != (i * BUFSIZE))
344 		filioerr(tfname);
345 }
346 #endif
347 
348 /*
349  * Synchronize the state of the temporary file in case
350  * a crash occurs.
351  */
352 synctmp()
353 {
354 	register int cnt;
355 	register line *a;
356 	register short *bp;
357 	register unsigned char *p1, *p2;
358 	register int n;
359 
360 #ifdef VMUNIX
361 	if (stilinc)
362 		return;
363 #endif
364 	if (dol == zero)
365 		return;
366 	/*
367 	 * In theory, we need to encrypt iblock and iblock2 before writing
368 	 * them out, as well as oblock, but in practice ichanged and ichang2
369 	 * can never be set, so this isn't really needed.  Likewise, the
370 	 * code in getblock above for iblock+iblock2 isn't needed.
371 	 */
372 	if (ichanged)
373 		blkio(iblock, ibuff, write);
374 	ichanged = 0;
375 	if (ichang2)
376 		blkio(iblock2, ibuff2, write);
377 	ichang2 = 0;
378 	if (oblock != -1)
379 	if (xtflag) {
380 		/*
381 		 * Encrypt block before writing, so some devious
382 		 * person can't look at temp file while editing.
383 		 */
384 		p1 = obuff;
385 		p2 = crbuf;
386 		n = CRSIZE;
387 		while (n--)
388 			*p2++ = *p1++;
389 			if (run_crypt(0L, crbuf, CRSIZE, tperm) == -1)
390 				filioerr(tfname);
391 		blkio(oblock, crbuf, write);
392 	} else
393 		blkio(oblock, obuff, write);
394 	time(&H.Time);
395 	uid = getuid();
396 	if (xtflag)
397 		H.encrypted = 1;
398 	else
399 		H.encrypted = 0;
400 	*zero = (line) H.Time;
401 	for (a = zero, bp = blocks; a <= dol;
402 					a += BUFSIZE / sizeof (*a), bp++) {
403 		if (bp >= &H.Blocks[LBLKS-1])
404 			error(gettext(
405 				"file too large to recover with -r option"));
406 		if (*bp < 0) {
407 			tline = (tline + OFFMSK) &~ OFFMSK;
408 			*bp = ((tline >> OFFBTS) & BLKMSK);
409 			if (*bp > NMBLKS)
410 				error(gettext(" Tmp file too large"));
411 			tline += INCRMT;
412 			oblock = *bp + 1;
413 			bp[1] = -1;
414 		}
415 		lseek(tfile, (long)(unsigned)*bp * BUFSIZE, 0);
416 		cnt = ((dol - a) + 2) * sizeof (line);
417 		if (cnt > BUFSIZE)
418 			cnt = BUFSIZE;
419 		if (write(tfile, (char *)a, cnt) != cnt) {
420 oops:
421 			*zero = 0;
422 			filioerr(tfname);
423 		}
424 		*zero = 0;
425 	}
426 	flines = lineDOL();
427 	lseek(tfile, 0l, 0);
428 	if (write(tfile, (char *)&H, sizeof (H)) != sizeof (H))
429 		goto oops;
430 }
431 
432 TSYNC()
433 {
434 
435 	if (dirtcnt > MAXDIRT) {
436 #ifdef VMUNIX
437 		if (stilinc)
438 			tflush();
439 #endif
440 		dirtcnt = 0;
441 		synctmp();
442 	}
443 }
444 
445 /*
446  * Named buffer routines.
447  * These are implemented differently than the main buffer.
448  * Each named buffer has a chain of blocks in the register file.
449  * Each block contains roughly 508 chars of text,
450  * and a previous and next block number.  We also have information
451  * about which blocks came from deletes of multiple partial lines,
452  * e.g. deleting a sentence or a LISP object.
453  *
454  * We maintain a free map for the temp file.  To free the blocks
455  * in a register we must read the blocks to find how they are chained
456  * together.
457  *
458  * BUG:		The default savind of deleted lines in numbered
459  *		buffers may be rather inefficient; it hasn't been profiled.
460  */
461 struct	strreg {
462 	short	rg_flags;
463 	short	rg_nleft;
464 	short	rg_first;
465 	short	rg_last;
466 } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp;
467 
468 struct	rbuf {
469 	short	rb_prev;
470 	short	rb_next;
471 	unsigned char	rb_text[BUFSIZE - 2 * sizeof (short)];
472 } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf;
473 #ifdef VMUNIX
474 short	rused[256];
475 #else
476 short	rused[32];
477 #endif
478 short	rnleft;
479 short	rblock;
480 short	rnext;
481 unsigned char	*rbufcp;
482 
483 regio(b, iofcn)
484 	short b;
485 	int (*iofcn)();
486 {
487 
488 	if (rfile == -1) {
489 		CP(rfname, tempname);
490 		(void) strcat(rfname, "/RxXXXXXX");
491 		if ((rfile = mkstemp((char *)rfname)) < 0)
492 			filioerr(rfname);
493 	}
494 	lseek(rfile, (long)b * BUFSIZE, 0);
495 	if ((*iofcn)(rfile, rbuf, BUFSIZE) != BUFSIZE)
496 		filioerr(rfname);
497 	rblock = b;
498 }
499 
500 REGblk()
501 {
502 	register int i, j, m;
503 
504 	for (i = 0; i < sizeof (rused) / sizeof (rused[0]); i++) {
505 		m = (rused[i] ^ 0177777) & 0177777;
506 		if (i == 0)
507 			m &= ~1;
508 		if (m != 0) {
509 			j = 0;
510 			while ((m & 1) == 0)
511 				j++, m >>= 1;
512 			rused[i] |= (1 << j);
513 #ifdef RDEBUG
514 			printf("allocating block %d\n", i * 16 + j);
515 #endif
516 			return (i * 16 + j);
517 		}
518 	}
519 	error(gettext("Out of register space (ugh)"));
520 	/*NOTREACHED*/
521 }
522 
523 struct	strreg *
524 mapreg(c)
525 	register int c;
526 {
527 
528 	if (isupper(c))
529 		c = tolower(c);
530 	return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
531 }
532 
533 int	shread();
534 
535 KILLreg(c)
536 	register int c;
537 {
538 	register struct strreg *sp;
539 
540 	rbuf = &KILLrbuf;
541 	sp = mapreg(c);
542 	rblock = sp->rg_first;
543 	sp->rg_first = sp->rg_last = 0;
544 	sp->rg_flags = sp->rg_nleft = 0;
545 	while (rblock != 0) {
546 #ifdef RDEBUG
547 		printf("freeing block %d\n", rblock);
548 #endif
549 		rused[rblock / 16] &= ~(1 << (rblock % 16));
550 		regio(rblock, shread);
551 		rblock = rbuf->rb_next;
552 	}
553 }
554 
555 /*VARARGS*/
556 shread()
557 {
558 	struct front { short a; short b; };
559 
560 	if (read(rfile, (char *)rbuf, sizeof (struct front)) ==
561 							sizeof (struct front))
562 		return (sizeof (struct rbuf));
563 	return (0);
564 }
565 
566 int	getREG();
567 
568 putreg(c)
569 	unsigned char c;
570 {
571 	register line *odot = dot;
572 	register line *odol = dol;
573 	register int cnt;
574 
575 	deletenone();
576 	appendnone();
577 	rbuf = &putrbuf;
578 	rnleft = 0;
579 	rblock = 0;
580 	rnext = mapreg(c)->rg_first;
581 	if (rnext == 0) {
582 		if (inopen) {
583 			splitw++;
584 			vclean();
585 			vgoto(WECHO, 0);
586 		}
587 		vreg = -1;
588 		error(gettext("Nothing in register %c"), c);
589 	}
590 	if (inopen && partreg(c)) {
591 		if (!FIXUNDO) {
592 			splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
593 			error(gettext("Can't put partial line inside macro"));
594 		}
595 		squish();
596 		addr1 = addr2 = dol;
597 	}
598 	cnt = append(getREG, addr2);
599 	if (inopen && partreg(c)) {
600 		unddol = dol;
601 		dol = odol;
602 		dot = odot;
603 		pragged(0);
604 	}
605 	killcnt(cnt);
606 	notecnt = cnt;
607 }
608 
609 partreg(c)
610 	unsigned char c;
611 {
612 
613 	return (mapreg(c)->rg_flags);
614 }
615 
616 notpart(c)
617 	register int c;
618 {
619 
620 	if (c)
621 		mapreg(c)->rg_flags = 0;
622 }
623 
624 getREG()
625 {
626 	register unsigned char *lp = linebuf;
627 	register int c;
628 
629 	for (;;) {
630 		if (rnleft == 0) {
631 			if (rnext == 0)
632 				return (EOF);
633 			regio(rnext, read);
634 			rnext = rbuf->rb_next;
635 			rbufcp = rbuf->rb_text;
636 			rnleft = sizeof (rbuf->rb_text);
637 		}
638 		c = *rbufcp;
639 		if (c == 0)
640 			return (EOF);
641 		rbufcp++, --rnleft;
642 		if (c == '\n') {
643 			*lp++ = 0;
644 			return (0);
645 		}
646 		*lp++ = c;
647 	}
648 }
649 
650 YANKreg(c)
651 	register int c;
652 {
653 	register line *addr;
654 	register struct strreg *sp;
655 	unsigned char savelb[LBSIZE];
656 
657 	if (isdigit(c))
658 		kshift();
659 	if (islower(c))
660 		KILLreg(c);
661 	strp = sp = mapreg(c);
662 	sp->rg_flags = inopen && cursor && wcursor;
663 	rbuf = &YANKrbuf;
664 	if (sp->rg_last) {
665 		regio(sp->rg_last, read);
666 		rnleft = sp->rg_nleft;
667 		rbufcp = &rbuf->rb_text[sizeof (rbuf->rb_text) - rnleft];
668 	} else {
669 		rblock = 0;
670 		rnleft = 0;
671 	}
672 	CP(savelb, linebuf);
673 	for (addr = addr1; addr <= addr2; addr++) {
674 		getline(*addr);
675 		if (sp->rg_flags) {
676 			if (addr == addr2)
677 				*wcursor = 0;
678 			if (addr == addr1)
679 				strcpy(linebuf, cursor);
680 		}
681 		YANKline();
682 	}
683 	rbflush();
684 	killed();
685 	CP(linebuf, savelb);
686 }
687 
688 kshift()
689 {
690 	register int i;
691 
692 	KILLreg('9');
693 	for (i = '8'; i >= '0'; i--)
694 		copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
695 }
696 
697 YANKline()
698 {
699 	register unsigned char *lp = linebuf;
700 	register struct rbuf *rp = rbuf;
701 	register int c;
702 
703 	do {
704 		c = *lp++;
705 		if (c == 0)
706 			c = '\n';
707 		if (rnleft == 0) {
708 			rp->rb_next = REGblk();
709 			rbflush();
710 			rblock = rp->rb_next;
711 			rp->rb_next = 0;
712 			rp->rb_prev = rblock;
713 			rnleft = sizeof (rp->rb_text);
714 			rbufcp = rp->rb_text;
715 		}
716 		*rbufcp++ = c;
717 		--rnleft;
718 	} while (c != '\n');
719 	if (rnleft)
720 		*rbufcp = 0;
721 }
722 
723 rbflush()
724 {
725 	register struct strreg *sp = strp;
726 
727 	if (rblock == 0)
728 		return;
729 	regio(rblock, write);
730 	if (sp->rg_first == 0)
731 		sp->rg_first = rblock;
732 	sp->rg_last = rblock;
733 	sp->rg_nleft = rnleft;
734 }
735 
736 /* Register c to char buffer buf of size buflen */
737 regbuf(c, buf, buflen)
738 unsigned char c;
739 unsigned char *buf;
740 int buflen;
741 {
742 	register unsigned char *p, *lp;
743 
744 	rbuf = &regrbuf;
745 	rnleft = 0;
746 	rblock = 0;
747 	rnext = mapreg(c)->rg_first;
748 	if (rnext == 0) {
749 		*buf = 0;
750 		error(gettext("Nothing in register %c"), c);
751 	}
752 	p = buf;
753 	while (getREG() == 0) {
754 		lp = linebuf;
755 		while (*lp) {
756 			if (p >= &buf[buflen])
757 				error(value(vi_TERSE) ?
758 gettext("Register too long") : gettext("Register too long to fit in memory"));
759 			*p++ = *lp++;
760 		}
761 		*p++ = '\n';
762 	}
763 	if (partreg(c)) p--;
764 	*p = '\0';
765 	getDOT();
766 }
767 
768 #ifdef TRACE
769 
770 /*
771  * Test code for displaying named registers.
772  */
773 
774 shownam()
775 {
776 	int k;
777 
778 	printf("\nRegister   Contents\n");
779 	printf("========   ========\n");
780 	for (k = 'a'; k <= 'z'; k++) {
781 		rbuf = &putrbuf;
782 		rnleft = 0;
783 		rblock = 0;
784 		rnext = mapreg(k)->rg_first;
785 		printf(" %c:", k);
786 		if (rnext == 0)
787 			printf("\t\tNothing in register.\n");
788 		while (getREG() == 0) {
789 			printf("\t\t%s\n", linebuf);
790 		}
791 	}
792 	return (0);
793 }
794 
795 /*
796  * Test code for displaying numbered registers.
797  */
798 
799 shownbr()
800 {
801 	int k;
802 
803 	printf("\nRegister   Contents\n");
804 	printf("========   ========\n");
805 	for (k = '1'; k <= '9'; k++) {
806 		rbuf = &putrbuf;
807 		rnleft = 0;
808 		rblock = 0;
809 		rnext = mapreg(k)->rg_first;
810 		printf(" %c:", k);
811 		if (rnext == 0)
812 			printf("\t\tNothing in register.\n");
813 		while (getREG() == 0) {
814 			printf("\t\t%s\n", linebuf);
815 		}
816 	}
817 	return (0);
818 }
819 #endif
820