|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char *sccsid = "@(#)ex_temp.c 7.7.1.1 (Berkeley) 10/21/90";
9: #endif not lint
10:
11: #include "ex.h"
12: #include "ex_temp.h"
13: #include "ex_vis.h"
14: #include "ex_tty.h"
15: #include "pathnames.h"
16:
17: /*
18: * Editor temporary file routines.
19: * Very similar to those of ed, except uses 2 input buffers.
20: */
21: #define READ 0
22: #define WRITE 1
23:
24: #ifndef vms
25: #define EPOSITION 7
26: #else
27: #define EPOSITION 13
28: #endif
29:
30: char tfname[40];
31: char rfname[40];
32: int havetmp;
33: short tfile = -1;
34: short rfile = -1;
35:
36: fileinit()
37: {
38: register char *p;
39: register int i, j;
40: struct stat stbuf;
41:
42: if (tline == INCRMT * (HBLKS+2))
43: return;
44: cleanup(0);
45: if (tfile >= 0)
46: close(tfile);
47: tline = INCRMT * (HBLKS+2);
48: blocks[0] = HBLKS;
49: blocks[1] = HBLKS+1;
50: blocks[2] = -1;
51: dirtcnt = 0;
52: iblock = -1;
53: iblock2 = -1;
54: oblock = -1;
55: CP(tfname, svalue(DIRECTORY));
56: #ifndef vms
57: if (stat(tfname, &stbuf))
58: #else
59: goto vms_no_check_dir;
60: #endif
61: {
62: dumbness:
63: if (setexit() == 0)
64: filioerr(tfname);
65: else
66: putNFL();
67: cleanup(1);
68: ex_exit(1);
69: }
70: #ifndef vms
71: if ((stbuf.st_mode & S_IFMT) != S_IFDIR) {
72: errno = ENOTDIR;
73: goto dumbness;
74: }
75: #else
76: vms_no_check_dir:
77: #endif
78: ichanged = 0;
79: ichang2 = 0;
80: #ifndef vms
81: ignore(strcat(tfname, "/ExXXXXX"));
82: #else
83: ignore(strcat(tfname, "ExXXXXX"));
84: #endif
85: for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10)
86: *--p = j % 10 | '0';
87: #ifdef vms
88: ignore(strcat(tfname, ".txt.1"));
89: unlink(tfname);
90: #endif
91: tfile = creat(tfname, 0600);
92: if (tfile < 0)
93: goto dumbness;
94: #ifdef VMUNIX
95: {
96: extern stilinc; /* see below */
97: stilinc = 0;
98: }
99: #endif
100: havetmp = 1;
101: if (tfile >= 0)
102: close(tfile);
103: tfile = open(tfname, 2);
104: if (tfile < 0)
105: goto dumbness;
106: #ifdef UNIX_SBRK
107: /* brk((char *)fendcore); */
108: #endif
109: }
110:
111: cleanup(all)
112: bool all;
113: {
114: if (all) {
115: putpad(TE);
116: flush();
117: }
118: if (havetmp) {
119: if (tfile >= 0)
120: close(tfile);
121: unlink(tfname);
122: }
123: havetmp = 0;
124: if (all && rfile >= 0) {
125: if (rfile >= 0)
126: close(rfile);
127: unlink(rfname);
128: rfile = -1;
129: }
130: }
131:
132: getline(tl)
133: line tl;
134: {
135: register char *bp, *lp;
136: register int nl;
137:
138: lp = linebuf;
139: bp = getblock(tl, READ);
140: nl = nleft;
141: tl &= ~OFFMSK;
142: while (*lp++ = *bp++)
143: if (--nl == 0) {
144: bp = getblock(tl += INCRMT, READ);
145: nl = nleft;
146: }
147: }
148:
149: putline()
150: {
151: register char *bp, *lp;
152: register int nl;
153: line tl;
154:
155: dirtcnt++;
156: lp = linebuf;
157: change();
158: tl = tline;
159: bp = getblock(tl, WRITE);
160: nl = nleft;
161: tl &= ~OFFMSK;
162: while (*bp = *lp++) {
163: if (*bp++ == '\n') {
164: *--bp = 0;
165: linebp = lp;
166: break;
167: }
168: if (--nl == 0) {
169: bp = getblock(tl += INCRMT, WRITE);
170: nl = nleft;
171: }
172: }
173: tl = tline;
174: tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776;
175: return (tl);
176: }
177:
178: int read();
179: int write();
180:
181: char *
182: getblock(atl, iof)
183: line atl;
184: int iof;
185: {
186: register int bno, off;
187:
188: bno = (atl >> OFFBTS) & BLKMSK;
189: off = (atl << SHFT) & LBTMSK;
190: if (bno >= NMBLKS)
191: error(" Tmp file too large");
192: nleft = BUFSIZ - off;
193: if (bno == iblock) {
194: ichanged |= iof;
195: hitin2 = 0;
196: return (ibuff + off);
197: }
198: if (bno == iblock2) {
199: ichang2 |= iof;
200: hitin2 = 1;
201: return (ibuff2 + off);
202: }
203: if (bno == oblock)
204: return (obuff + off);
205: if (iof == READ) {
206: if (hitin2 == 0) {
207: if (ichang2) {
208: blkio(iblock2, ibuff2, write);
209: }
210: ichang2 = 0;
211: iblock2 = bno;
212: blkio(bno, ibuff2, read);
213: hitin2 = 1;
214: return (ibuff2 + off);
215: }
216: hitin2 = 0;
217: if (ichanged) {
218: blkio(iblock, ibuff, write);
219: }
220: ichanged = 0;
221: iblock = bno;
222: blkio(bno, ibuff, read);
223: return (ibuff + off);
224: }
225: if (oblock >= 0) {
226: blkio(oblock, obuff, write);
227: }
228: oblock = bno;
229: return (obuff + off);
230: }
231:
232: #ifdef VMUNIX
233: #ifdef vms
234: #define INCORB 32
235: #else
236: #define INCORB 64
237: #endif
238: char incorb[INCORB+1][BUFSIZ];
239: #define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1)))
240: int stilinc; /* up to here not written yet */
241: #endif
242:
243: blkio(b, buf, iofcn)
244: short b;
245: char *buf;
246: int (*iofcn)();
247: {
248:
249: #ifdef VMUNIX
250: if (b < INCORB) {
251: if (iofcn == read) {
252: bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ);
253: return;
254: }
255: bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ);
256: if (laste) {
257: if (b >= stilinc)
258: stilinc = b + 1;
259: return;
260: }
261: } else if (stilinc)
262: tflush();
263: #endif
264: lseek(tfile, (long) (unsigned) b * BUFSIZ, 0);
265: if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
266: filioerr(tfname);
267: }
268:
269: #ifdef VMUNIX
270: tlaste()
271: {
272:
273: if (stilinc)
274: dirtcnt = 0;
275: }
276:
277: tflush()
278: {
279: int i = stilinc;
280:
281: stilinc = 0;
282: lseek(tfile, (long) 0, 0);
283: if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ))
284: filioerr(tfname);
285: }
286: #endif
287:
288: /*
289: * Synchronize the state of the temporary file in case
290: * a crash occurs.
291: */
292: synctmp()
293: {
294: register int cnt;
295: register line *a;
296: register short *bp;
297:
298: #ifdef VMUNIX
299: if (stilinc)
300: return;
301: #endif
302: if (dol == zero)
303: return;
304: if (ichanged)
305: blkio(iblock, ibuff, write);
306: ichanged = 0;
307: if (ichang2)
308: blkio(iblock2, ibuff2, write);
309: ichang2 = 0;
310: if (oblock != -1)
311: blkio(oblock, obuff, write);
312: time(&H.Time);
313: uid = getuid();
314: *zero = (line) H.Time;
315: for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) {
316: if (*bp < 0) {
317: tline = (tline + OFFMSK) &~ OFFMSK;
318: *bp = ((tline >> OFFBTS) & BLKMSK);
319: if (*bp > NMBLKS)
320: error(" Tmp file too large");
321: tline += INCRMT;
322: oblock = *bp + 1;
323: bp[1] = -1;
324: }
325: lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0);
326: cnt = ((dol - a) + 2) * sizeof (line);
327: if (cnt > BUFSIZ)
328: cnt = BUFSIZ;
329: if (write(tfile, (char *) a, cnt) != cnt) {
330: oops:
331: *zero = 0;
332: filioerr(tfname);
333: }
334: *zero = 0;
335: }
336: flines = lineDOL();
337: lseek(tfile, 0l, 0);
338: if (write(tfile, (char *) &H, sizeof H) != sizeof H)
339: goto oops;
340: #ifdef notdef
341: /*
342: * This will insure that exrecover gets as much
343: * back after a crash as is absolutely possible,
344: * but can result in pregnant pauses between commands
345: * when the TSYNC call is made, so...
346: */
347: #ifndef vms
348: (void) fsync(tfile);
349: #endif
350: #endif
351: }
352:
353: TSYNC()
354: {
355:
356: if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */
357: #ifdef VMUNIX
358: if (stilinc)
359: tflush();
360: #endif
361: dirtcnt = 0;
362: synctmp();
363: }
364: }
365:
366: /*
367: * Named buffer routines.
368: * These are implemented differently than the main buffer.
369: * Each named buffer has a chain of blocks in the register file.
370: * Each block contains roughly 508 chars of text,
371: * and a previous and next block number. We also have information
372: * about which blocks came from deletes of multiple partial lines,
373: * e.g. deleting a sentence or a LISP object.
374: *
375: * We maintain a free map for the temp file. To free the blocks
376: * in a register we must read the blocks to find how they are chained
377: * together.
378: *
379: * BUG: The default savind of deleted lines in numbered
380: * buffers may be rather inefficient; it hasn't been profiled.
381: */
382: struct strreg {
383: short rg_flags;
384: short rg_nleft;
385: short rg_first;
386: short rg_last;
387: } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp;
388:
389: struct rbuf {
390: short rb_prev;
391: short rb_next;
392: char rb_text[BUFSIZ - 2 * sizeof (short)];
393: } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf;
394: #ifdef VMUNIX
395: short rused[256];
396: #else
397: short rused[32];
398: #endif
399: short rnleft;
400: short rblock;
401: short rnext;
402: char *rbufcp;
403:
404: regio(b, iofcn)
405: short b;
406: int (*iofcn)();
407: {
408:
409: if (rfile == -1) {
410: CP(rfname, tfname);
411: *(strend(rfname) - EPOSITION) = 'R';
412: rfile = creat(rfname, 0600);
413: if (rfile < 0)
414: oops:
415: filioerr(rfname);
416: else
417: close(rfile);
418: rfile = open(rfname, 2);
419: if (rfile < 0)
420: goto oops;
421: }
422: lseek(rfile, (long) b * BUFSIZ, 0);
423: if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ)
424: goto oops;
425: rblock = b;
426: }
427:
428: REGblk()
429: {
430: register int i, j, m;
431:
432: for (i = 0; i < sizeof rused / sizeof rused[0]; i++) {
433: m = (rused[i] ^ 0177777) & 0177777;
434: if (i == 0)
435: m &= ~1;
436: if (m != 0) {
437: j = 0;
438: while ((m & 1) == 0)
439: j++, m >>= 1;
440: rused[i] |= (1 << j);
441: #ifdef RDEBUG
442: ex_printf("allocating block %d\n", i * 16 + j);
443: #endif
444: return (i * 16 + j);
445: }
446: }
447: error("Out of register space (ugh)");
448: /*NOTREACHED*/
449: }
450:
451: struct strreg *
452: mapreg(c)
453: register int c;
454: {
455:
456: if (isupper(c))
457: c = tolower(c);
458: return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
459: }
460:
461: int shread();
462:
463: KILLreg(c)
464: register int c;
465: {
466: register struct strreg *sp;
467:
468: rbuf = &KILLrbuf;
469: sp = mapreg(c);
470: rblock = sp->rg_first;
471: sp->rg_first = sp->rg_last = 0;
472: sp->rg_flags = sp->rg_nleft = 0;
473: while (rblock != 0) {
474: #ifdef RDEBUG
475: ex_printf("freeing block %d\n", rblock);
476: #endif
477: rused[rblock / 16] &= ~(1 << (rblock % 16));
478: regio(rblock, shread);
479: rblock = rbuf->rb_next;
480: }
481: }
482:
483: /*VARARGS*/
484: shread()
485: {
486: struct front { short a; short b; };
487:
488: if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front))
489: return (sizeof (struct rbuf));
490: return (0);
491: }
492:
493: int getREG();
494:
495: putreg(c)
496: char c;
497: {
498: register line *odot = dot;
499: register line *odol = dol;
500: register int cnt;
501:
502: deletenone();
503: appendnone();
504: rbuf = &putrbuf;
505: rnleft = 0;
506: rblock = 0;
507: rnext = mapreg(c)->rg_first;
508: if (rnext == 0) {
509: if (inopen) {
510: splitw++;
511: vclean();
512: vgoto(WECHO, 0);
513: }
514: vreg = -1;
515: error("Nothing in register %c", c);
516: }
517: if (inopen && partreg(c)) {
518: if (!FIXUNDO) {
519: splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
520: error("Can't put partial line inside macro");
521: }
522: squish();
523: addr1 = addr2 = dol;
524: }
525: cnt = append(getREG, addr2);
526: if (inopen && partreg(c)) {
527: unddol = dol;
528: dol = odol;
529: dot = odot;
530: pragged(0);
531: }
532: killcnt(cnt);
533: notecnt = cnt;
534: }
535:
536: partreg(c)
537: char c;
538: {
539:
540: return (mapreg(c)->rg_flags);
541: }
542:
543: notpart(c)
544: register int c;
545: {
546:
547: if (c)
548: mapreg(c)->rg_flags = 0;
549: }
550:
551: getREG()
552: {
553: register char *lp = linebuf;
554: register int c;
555:
556: for (;;) {
557: if (rnleft == 0) {
558: if (rnext == 0)
559: return (EOF);
560: regio(rnext, read);
561: rnext = rbuf->rb_next;
562: rbufcp = rbuf->rb_text;
563: rnleft = sizeof rbuf->rb_text;
564: }
565: c = *rbufcp;
566: if (c == 0)
567: return (EOF);
568: rbufcp++, --rnleft;
569: if (c == '\n') {
570: *lp++ = 0;
571: return (0);
572: }
573: *lp++ = c;
574: }
575: }
576:
577: YANKreg(c)
578: register int c;
579: {
580: register line *addr;
581: register struct strreg *sp;
582: char savelb[LBSIZE];
583:
584: if (isdigit(c))
585: kshift();
586: if (islower(c))
587: KILLreg(c);
588: strp = sp = mapreg(c);
589: sp->rg_flags = inopen && cursor && wcursor;
590: rbuf = &YANKrbuf;
591: if (sp->rg_last) {
592: regio(sp->rg_last, read);
593: rnleft = sp->rg_nleft;
594: rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
595: } else {
596: rblock = 0;
597: rnleft = 0;
598: }
599: CP(savelb,linebuf);
600: for (addr = addr1; addr <= addr2; addr++) {
601: getline(*addr);
602: if (sp->rg_flags) {
603: if (addr == addr2)
604: *wcursor = 0;
605: if (addr == addr1)
606: strcpy(linebuf, cursor);
607: }
608: YANKline();
609: }
610: rbflush();
611: killed();
612: CP(linebuf,savelb);
613: }
614:
615: kshift()
616: {
617: register int i;
618:
619: KILLreg('9');
620: for (i = '8'; i >= '0'; i--)
621: copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
622: }
623:
624: YANKline()
625: {
626: register char *lp = linebuf;
627: register struct rbuf *rp = rbuf;
628: register int c;
629:
630: do {
631: c = *lp++;
632: if (c == 0)
633: c = '\n';
634: if (rnleft == 0) {
635: rp->rb_next = REGblk();
636: rbflush();
637: rblock = rp->rb_next;
638: rp->rb_next = 0;
639: rp->rb_prev = rblock;
640: rnleft = sizeof rp->rb_text;
641: rbufcp = rp->rb_text;
642: }
643: *rbufcp++ = c;
644: --rnleft;
645: } while (c != '\n');
646: if (rnleft)
647: *rbufcp = 0;
648: }
649:
650: rbflush()
651: {
652: register struct strreg *sp = strp;
653:
654: if (rblock == 0)
655: return;
656: regio(rblock, write);
657: if (sp->rg_first == 0)
658: sp->rg_first = rblock;
659: sp->rg_last = rblock;
660: sp->rg_nleft = rnleft;
661: }
662:
663: /* Register c to char buffer buf of size buflen */
664: regbuf(c, buf, buflen)
665: char c;
666: char *buf;
667: int buflen;
668: {
669: register char *p, *lp;
670:
671: rbuf = ®rbuf;
672: rnleft = 0;
673: rblock = 0;
674: rnext = mapreg(c)->rg_first;
675: if (rnext==0) {
676: *buf = 0;
677: error("Nothing in register %c",c);
678: }
679: p = buf;
680: while (getREG()==0) {
681: for (lp=linebuf; *lp;) {
682: if (p >= &buf[buflen])
683: error("Register too long@to fit in memory");
684: *p++ = *lp++;
685: }
686: *p++ = '\n';
687: }
688: if (partreg(c)) p--;
689: *p = '\0';
690: getDOT();
691: }
692:
693: /*
694: * Encryption routines. These are essentially unmodified from ed.
695: */
696:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.