8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / cmd / vi / port / ex_temp.c
blob95fcdbf2b6de7da26c2b644280badd240e5de5fc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 /* Copyright (c) 1981 Regents of the University of California */
32 #include "ex.h"
33 #include "ex_temp.h"
34 #include "ex_vis.h"
35 #include "ex_tty.h"
36 #include <unistd.h>
39 * Editor temporary file routines.
40 * Very similar to those of ed, except uses 2 input buffers.
42 #define READ 0
43 #define WRITE 1
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;
52 extern int junk();
54 void
55 fileinit(void)
57 unsigned char *p;
58 pid_t j;
59 int i;
60 struct stat64 stbuf;
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);
87 if (!ISDIR(stbuf)) {
88 errno = ENOTDIR;
89 goto dumbness;
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
99 extern int stilinc; /* see below */
100 stilinc = 0;
102 #endif
103 havetmp = 1;
104 /* brk((unsigned char *)fendcore); */
107 void
108 cleanup(bool all)
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);
127 #endif /* XPG4 */
128 resetterm();
129 normtty--;
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);
139 #endif /* XPG4 */
140 resetterm();
141 normtty--;
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;
152 if (all == 1)
153 exit(errcnt);
156 void
157 getaline(line tl)
159 unsigned char *bp, *lp;
160 int nl;
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;
174 putline(void)
176 unsigned char *bp, *lp;
177 unsigned char tmpbp;
178 int nl;
179 line tl;
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;
198 if (--nl == 0) {
199 bp = getblock(tl += INCRMT, WRITE);
200 nl = nleft;
203 tl = tline;
204 tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776;
205 return (tl);
208 int read();
209 int write();
211 unsigned char *
212 getblock(line atl, int iof)
214 int bno, off;
215 unsigned char *p1, *p2;
216 int n;
217 line *tmpptr;
219 bno = (atl >> OFFBTS) & BLKMSK;
220 off = (atl << SHFT) & LBTMSK;
221 if (bno >= NMBLKS) {
223 * When we overflow tmpfile buffers,
224 * throw away line which could not be
225 * put into buffer.
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"));
235 nleft = BUFSIZE - off;
236 if (bno == iblock) {
237 ichanged |= iof;
238 hitin2 = 0;
239 return (ibuff + off);
241 if (bno == iblock2) {
242 ichang2 |= iof;
243 hitin2 = 1;
244 return (ibuff2 + off);
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);
257 blkio(iblock2, ibuff2, write);
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);
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);
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);
283 if (oblock >= 0) {
284 if (xtflag) {
286 * Encrypt block before writing, so some devious
287 * person can't look at temp file while editing.
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);
300 oblock = bno;
301 return (obuff + off);
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
311 void
312 blkio(short b, unsigned char *buf, int (*iofcn)())
315 #ifdef VMUNIX
316 if (b < INCORB) {
317 if (iofcn == read) {
318 bcopy(pagrnd(incorb[b+1]), buf, BUFSIZE);
319 return;
321 bcopy(buf, pagrnd(incorb[b+1]), BUFSIZE);
322 if (laste) {
323 if (b >= stilinc)
324 stilinc = b + 1;
325 return;
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);
335 #ifdef VMUNIX
336 void
337 tlaste(void)
340 if (stilinc)
341 dirtcnt = 0;
344 void
345 tflush(void)
347 int i = stilinc;
349 stilinc = 0;
350 lseek(tfile, (long)0, 0);
351 if (write(tfile, pagrnd(incorb[1]), i * BUFSIZE) != (i * BUFSIZE))
352 filioerr(tfname);
354 #endif
357 * Synchronize the state of the temporary file in case
358 * a crash occurs.
360 void
361 synctmp(void)
363 int cnt;
364 line *a;
365 short *bp;
366 unsigned char *p1, *p2;
367 int n;
369 #ifdef VMUNIX
370 if (stilinc)
371 return;
372 #endif
373 if (dol == zero)
374 return;
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.
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) {
390 * Encrypt block before writing, so some devious
391 * person can't look at temp file while editing.
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;
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);
433 *zero = 0;
435 flines = lineDOL();
436 lseek(tfile, 0l, 0);
437 if (write(tfile, (char *)&H, sizeof (H)) != sizeof (H))
438 goto oops;
441 void
442 TSYNC(void)
445 if (dirtcnt > MAXDIRT) {
446 #ifdef VMUNIX
447 if (stilinc)
448 tflush();
449 #endif
450 dirtcnt = 0;
451 synctmp();
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.
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.
468 * BUG: The default savind of deleted lines in numbered
469 * buffers may be rather inefficient; it hasn't been profiled.
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;
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;
493 void
494 regio(short b, int (*iofcn)())
497 if (rfile == -1) {
498 CP(rfname, tempname);
499 (void) strcat(rfname, "/RxXXXXXX");
500 if ((rfile = mkstemp((char *)rfname)) < 0)
501 filioerr(rfname);
503 lseek(rfile, (long)b * BUFSIZE, 0);
504 if ((*iofcn)(rfile, rbuf, BUFSIZE) != BUFSIZE)
505 filioerr(rfname);
506 rblock = b;
510 REGblk(void)
512 int i, j, m;
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);
529 error(gettext("Out of register space (ugh)"));
530 /*NOTREACHED*/
531 return (0);
534 struct strreg *
535 mapreg(int c)
538 if (isupper(c))
539 c = tolower(c);
540 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
543 int shread();
545 void
546 KILLreg(int c)
548 struct strreg *sp;
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;
565 /*VARARGS*/
567 shread(void)
569 struct front { short a; short b; };
571 if (read(rfile, (char *)rbuf, sizeof (struct front)) ==
572 sizeof (struct front))
573 return (sizeof (struct rbuf));
574 return (0);
577 int getREG();
580 putreg(unsigned char c)
582 line *odot = dot;
583 line *odol = dol;
584 int cnt;
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);
598 vreg = -1;
599 error(gettext("Nothing in register %c"), c);
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"));
606 squish();
607 addr1 = addr2 = dol;
609 cnt = append(getREG, addr2);
610 if (inopen && partreg(c)) {
611 unddol = dol;
612 dol = odol;
613 dot = odot;
614 pragged(0);
616 killcnt(cnt);
617 notecnt = cnt;
618 return (0);
621 short
622 partreg(unsigned char c)
625 return (mapreg(c)->rg_flags);
628 void
629 notpart(int c)
632 if (c)
633 mapreg(c)->rg_flags = 0;
637 getREG(void)
639 unsigned char *lp = linebuf;
640 int c;
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);
651 c = *rbufcp;
652 if (c == 0)
653 return (EOF);
654 rbufcp++, --rnleft;
655 if (c == '\n') {
656 *lp++ = 0;
657 return (0);
659 *lp++ = c;
664 YANKreg(int c)
666 line *addr;
667 struct strreg *sp;
668 unsigned char savelb[LBSIZE];
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;
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);
694 YANKline();
696 rbflush();
697 killed();
698 CP(linebuf, savelb);
699 return (0);
702 void
703 kshift(void)
705 int i;
707 KILLreg('9');
708 for (i = '8'; i >= '0'; i--)
709 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
712 void
713 YANKline(void)
715 unsigned char *lp = linebuf;
716 struct rbuf *rp = rbuf;
717 int c;
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;
732 *rbufcp++ = c;
733 --rnleft;
734 } while (c != '\n');
735 if (rnleft)
736 *rbufcp = 0;
739 void
740 rbflush(void)
742 struct strreg *sp = strp;
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;
753 /* Register c to char buffer buf of size buflen */
754 void
755 regbuf(unsigned char c, unsigned char *buf, int buflen)
757 unsigned char *p, *lp;
759 rbuf = &regrbuf;
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);
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++;
776 *p++ = '\n';
778 if (partreg(c)) p--;
779 *p = '\0';
780 getDOT();
783 #ifdef TRACE
786 * Test code for displaying named registers.
789 shownam()
791 int k;
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);
807 return (0);
811 * Test code for displaying numbered registers.
814 shownbr()
816 int k;
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);
832 return (0);
834 #endif