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