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(line atl,int iof)212 getblock(line atl, int iof)
213 {
214 int bno, off;
215 unsigned char *p1, *p2;
216 int n;
217 line *tmpptr;
218
219 bno = (atl >> OFFBTS) & BLKMSK;
220 off = (atl << SHFT) & LBTMSK;
221 if (bno >= NMBLKS) {
222 /*
223 * When we overflow tmpfile buffers,
224 * throw away line which could not be
225 * put into buffer.
226 */
227 for (tmpptr = dot; tmpptr < unddol; tmpptr++)
228 *tmpptr = *(tmpptr+1);
229 if (dot == dol)
230 dot--;
231 dol--;
232 unddol--;
233 error(gettext(" Tmp file too large"));
234 }
235 nleft = BUFSIZE - off;
236 if (bno == iblock) {
237 ichanged |= iof;
238 hitin2 = 0;
239 return (ibuff + off);
240 }
241 if (bno == iblock2) {
242 ichang2 |= iof;
243 hitin2 = 1;
244 return (ibuff2 + off);
245 }
246 if (bno == oblock)
247 return (obuff + off);
248 if (iof == READ) {
249 if (hitin2 == 0) {
250 if (ichang2) {
251 if (xtflag) {
252 if (run_crypt(0L, ibuff2,
253 CRSIZE, tperm) == -1) {
254 filioerr(tfname);
255 }
256 }
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(int c)535 mapreg(int c)
536 {
537
538 if (isupper(c))
539 c = tolower(c);
540 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
541 }
542
543 int shread();
544
545 void
KILLreg(int c)546 KILLreg(int c)
547 {
548 struct strreg *sp;
549
550 rbuf = &KILLrbuf;
551 sp = mapreg(c);
552 rblock = sp->rg_first;
553 sp->rg_first = sp->rg_last = 0;
554 sp->rg_flags = sp->rg_nleft = 0;
555 while (rblock != 0) {
556 #ifdef RDEBUG
557 viprintf("freeing block %d\n", rblock);
558 #endif
559 rused[rblock / 16] &= ~(1 << (rblock % 16));
560 regio(rblock, shread);
561 rblock = rbuf->rb_next;
562 }
563 }
564
565 /*VARARGS*/
566 int
shread(void)567 shread(void)
568 {
569 struct front { short a; short b; };
570
571 if (read(rfile, (char *)rbuf, sizeof (struct front)) ==
572 sizeof (struct front))
573 return (sizeof (struct rbuf));
574 return (0);
575 }
576
577 int getREG();
578
579 int
putreg(unsigned char c)580 putreg(unsigned char c)
581 {
582 line *odot = dot;
583 line *odol = dol;
584 int cnt;
585
586 deletenone();
587 appendnone();
588 rbuf = &putrbuf;
589 rnleft = 0;
590 rblock = 0;
591 rnext = mapreg(c)->rg_first;
592 if (rnext == 0) {
593 if (inopen) {
594 splitw++;
595 vclean();
596 vgoto(WECHO, 0);
597 }
598 vreg = -1;
599 error(gettext("Nothing in register %c"), c);
600 }
601 if (inopen && partreg(c)) {
602 if (!FIXUNDO) {
603 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
604 error(gettext("Can't put partial line inside macro"));
605 }
606 squish();
607 addr1 = addr2 = dol;
608 }
609 cnt = append(getREG, addr2);
610 if (inopen && partreg(c)) {
611 unddol = dol;
612 dol = odol;
613 dot = odot;
614 pragged(0);
615 }
616 killcnt(cnt);
617 notecnt = cnt;
618 return (0);
619 }
620
621 short
partreg(unsigned char c)622 partreg(unsigned char c)
623 {
624
625 return (mapreg(c)->rg_flags);
626 }
627
628 void
notpart(int c)629 notpart(int c)
630 {
631
632 if (c)
633 mapreg(c)->rg_flags = 0;
634 }
635
636 int
getREG(void)637 getREG(void)
638 {
639 unsigned char *lp = linebuf;
640 int c;
641
642 for (;;) {
643 if (rnleft == 0) {
644 if (rnext == 0)
645 return (EOF);
646 regio(rnext, read);
647 rnext = rbuf->rb_next;
648 rbufcp = rbuf->rb_text;
649 rnleft = sizeof (rbuf->rb_text);
650 }
651 c = *rbufcp;
652 if (c == 0)
653 return (EOF);
654 rbufcp++, --rnleft;
655 if (c == '\n') {
656 *lp++ = 0;
657 return (0);
658 }
659 *lp++ = c;
660 }
661 }
662
663 int
YANKreg(int c)664 YANKreg(int c)
665 {
666 line *addr;
667 struct strreg *sp;
668 unsigned char savelb[LBSIZE];
669
670 if (isdigit(c))
671 kshift();
672 if (islower(c))
673 KILLreg(c);
674 strp = sp = mapreg(c);
675 sp->rg_flags = inopen && cursor && wcursor;
676 rbuf = &YANKrbuf;
677 if (sp->rg_last) {
678 regio(sp->rg_last, read);
679 rnleft = sp->rg_nleft;
680 rbufcp = &rbuf->rb_text[sizeof (rbuf->rb_text) - rnleft];
681 } else {
682 rblock = 0;
683 rnleft = 0;
684 }
685 CP(savelb, linebuf);
686 for (addr = addr1; addr <= addr2; addr++) {
687 getaline(*addr);
688 if (sp->rg_flags) {
689 if (addr == addr2)
690 *wcursor = 0;
691 if (addr == addr1)
692 strcpy(linebuf, cursor);
693 }
694 YANKline();
695 }
696 rbflush();
697 killed();
698 CP(linebuf, savelb);
699 return (0);
700 }
701
702 void
kshift(void)703 kshift(void)
704 {
705 int i;
706
707 KILLreg('9');
708 for (i = '8'; i >= '0'; i--)
709 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
710 }
711
712 void
YANKline(void)713 YANKline(void)
714 {
715 unsigned char *lp = linebuf;
716 struct rbuf *rp = rbuf;
717 int c;
718
719 do {
720 c = *lp++;
721 if (c == 0)
722 c = '\n';
723 if (rnleft == 0) {
724 rp->rb_next = REGblk();
725 rbflush();
726 rblock = rp->rb_next;
727 rp->rb_next = 0;
728 rp->rb_prev = rblock;
729 rnleft = sizeof (rp->rb_text);
730 rbufcp = rp->rb_text;
731 }
732 *rbufcp++ = c;
733 --rnleft;
734 } while (c != '\n');
735 if (rnleft)
736 *rbufcp = 0;
737 }
738
739 void
rbflush(void)740 rbflush(void)
741 {
742 struct strreg *sp = strp;
743
744 if (rblock == 0)
745 return;
746 regio(rblock, write);
747 if (sp->rg_first == 0)
748 sp->rg_first = rblock;
749 sp->rg_last = rblock;
750 sp->rg_nleft = rnleft;
751 }
752
753 /* Register c to char buffer buf of size buflen */
754 void
regbuf(unsigned char c,unsigned char * buf,int buflen)755 regbuf(unsigned char c, unsigned char *buf, int buflen)
756 {
757 unsigned char *p, *lp;
758
759 rbuf = ®rbuf;
760 rnleft = 0;
761 rblock = 0;
762 rnext = mapreg(c)->rg_first;
763 if (rnext == 0) {
764 *buf = 0;
765 error(gettext("Nothing in register %c"), c);
766 }
767 p = buf;
768 while (getREG() == 0) {
769 lp = linebuf;
770 while (*lp) {
771 if (p >= &buf[buflen])
772 error(value(vi_TERSE) ?
773 gettext("Register too long") : gettext("Register too long to fit in memory"));
774 *p++ = *lp++;
775 }
776 *p++ = '\n';
777 }
778 if (partreg(c)) p--;
779 *p = '\0';
780 getDOT();
781 }
782
783 #ifdef TRACE
784
785 /*
786 * Test code for displaying named registers.
787 */
788
shownam()789 shownam()
790 {
791 int k;
792
793 viprintf("\nRegister Contents\n");
794 viprintf("======== ========\n");
795 for (k = 'a'; k <= 'z'; k++) {
796 rbuf = &putrbuf;
797 rnleft = 0;
798 rblock = 0;
799 rnext = mapreg(k)->rg_first;
800 viprintf(" %c:", k);
801 if (rnext == 0)
802 viprintf("\t\tNothing in register.\n");
803 while (getREG() == 0) {
804 viprintf("\t\t%s\n", linebuf);
805 }
806 }
807 return (0);
808 }
809
810 /*
811 * Test code for displaying numbered registers.
812 */
813
shownbr()814 shownbr()
815 {
816 int k;
817
818 viprintf("\nRegister Contents\n");
819 viprintf("======== ========\n");
820 for (k = '1'; k <= '9'; k++) {
821 rbuf = &putrbuf;
822 rnleft = 0;
823 rblock = 0;
824 rnext = mapreg(k)->rg_first;
825 viprintf(" %c:", k);
826 if (rnext == 0)
827 viprintf("\t\tNothing in register.\n");
828 while (getREG() == 0) {
829 viprintf("\t\t%s\n", linebuf);
830 }
831 }
832 return (0);
833 }
834 #endif
835