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