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