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