use btree instead of hashing, don't have to resort later
[unix-history] / usr / src / usr.bin / ex / ex_temp.c
CommitLineData
2791ff57
KB
1/*-
2 * Copyright (c) 1980 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
70190965
JB
6 */
7
8#ifndef lint
2791ff57
KB
9static char sccsid[] = "@(#)ex_temp.c 7.8 (Berkeley) %G%";
10#endif /* not lint */
70190965 11
d4a8288f
MH
12#include "ex.h"
13#include "ex_temp.h"
14#include "ex_vis.h"
15#include "ex_tty.h"
435e8dff 16#include "pathnames.h"
d4a8288f
MH
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
5a6c967e
CH
25#ifndef vms
26#define EPOSITION 7
27#else
28#define EPOSITION 13
29#endif
30
d4a8288f
MH
31char tfname[40];
32char rfname[40];
33int havetmp;
cb3ac212 34short tfile = -1;
d4a8288f
MH
35short rfile = -1;
36
37fileinit()
38{
39 register char *p;
40 register int i, j;
41 struct stat stbuf;
42
44232d5b 43 if (tline == INCRMT * (HBLKS+2))
d4a8288f
MH
44 return;
45 cleanup(0);
5a6c967e
CH
46 if (tfile >= 0)
47 close(tfile);
44232d5b
MH
48 tline = INCRMT * (HBLKS+2);
49 blocks[0] = HBLKS;
50 blocks[1] = HBLKS+1;
d4a8288f
MH
51 blocks[2] = -1;
52 dirtcnt = 0;
53 iblock = -1;
54 iblock2 = -1;
55 oblock = -1;
56 CP(tfname, svalue(DIRECTORY));
5a6c967e
CH
57#ifndef vms
58 if (stat(tfname, &stbuf))
59#else
60 goto vms_no_check_dir;
61#endif
62 {
d4a8288f
MH
63dumbness:
64 if (setexit() == 0)
65 filioerr(tfname);
66 else
67 putNFL();
68 cleanup(1);
5a6c967e 69 ex_exit(1);
d4a8288f 70 }
5a6c967e 71#ifndef vms
d4a8288f
MH
72 if ((stbuf.st_mode & S_IFMT) != S_IFDIR) {
73 errno = ENOTDIR;
74 goto dumbness;
75 }
5a6c967e
CH
76#else
77vms_no_check_dir:
78#endif
d4a8288f
MH
79 ichanged = 0;
80 ichang2 = 0;
5a6c967e 81#ifndef vms
d4a8288f 82 ignore(strcat(tfname, "/ExXXXXX"));
5a6c967e
CH
83#else
84 ignore(strcat(tfname, "ExXXXXX"));
85#endif
d4a8288f
MH
86 for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10)
87 *--p = j % 10 | '0';
5a6c967e
CH
88#ifdef vms
89 ignore(strcat(tfname, ".txt.1"));
90 unlink(tfname);
91#endif
d4a8288f
MH
92 tfile = creat(tfname, 0600);
93 if (tfile < 0)
94 goto dumbness;
7c4625ef
MH
95#ifdef VMUNIX
96 {
97 extern stilinc; /* see below */
98 stilinc = 0;
99 }
100#endif
d4a8288f 101 havetmp = 1;
5a6c967e
CH
102 if (tfile >= 0)
103 close(tfile);
d4a8288f
MH
104 tfile = open(tfname, 2);
105 if (tfile < 0)
106 goto dumbness;
5a6c967e 107#ifdef UNIX_SBRK
d4a8288f 108/* brk((char *)fendcore); */
5a6c967e 109#endif
d4a8288f
MH
110}
111
112cleanup(all)
113 bool all;
114{
115 if (all) {
116 putpad(TE);
117 flush();
118 }
5a6c967e
CH
119 if (havetmp) {
120 if (tfile >= 0)
121 close(tfile);
d4a8288f 122 unlink(tfname);
5a6c967e 123 }
d4a8288f
MH
124 havetmp = 0;
125 if (all && rfile >= 0) {
5a6c967e
CH
126 if (rfile >= 0)
127 close(rfile);
d4a8288f 128 unlink(rfname);
d4a8288f
MH
129 rfile = -1;
130 }
131}
132
133getline(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
150putline()
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
179int read();
180int write();
181
182char *
183getblock(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) {
d266c416 208 if (ichang2) {
d4a8288f 209 blkio(iblock2, ibuff2, write);
d266c416 210 }
d4a8288f
MH
211 ichang2 = 0;
212 iblock2 = bno;
213 blkio(bno, ibuff2, read);
214 hitin2 = 1;
215 return (ibuff2 + off);
216 }
217 hitin2 = 0;
d266c416 218 if (ichanged) {
d4a8288f 219 blkio(iblock, ibuff, write);
d266c416 220 }
d4a8288f
MH
221 ichanged = 0;
222 iblock = bno;
223 blkio(bno, ibuff, read);
224 return (ibuff + off);
225 }
d266c416 226 if (oblock >= 0) {
d266c416
MH
227 blkio(oblock, obuff, write);
228 }
d4a8288f
MH
229 oblock = bno;
230 return (obuff + off);
231}
232
7c4625ef 233#ifdef VMUNIX
5a6c967e
CH
234#ifdef vms
235#define INCORB 32
236#else
7c4625ef 237#define INCORB 64
5a6c967e 238#endif
7c4625ef
MH
239char incorb[INCORB+1][BUFSIZ];
240#define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1)))
241int stilinc; /* up to here not written yet */
242#endif
243
d4a8288f
MH
244blkio(b, buf, iofcn)
245 short b;
246 char *buf;
247 int (*iofcn)();
248{
249
7c4625ef
MH
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
d4a8288f
MH
265 lseek(tfile, (long) (unsigned) b * BUFSIZ, 0);
266 if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
267 filioerr(tfname);
268}
269
7c4625ef
MH
270#ifdef VMUNIX
271tlaste()
272{
273
274 if (stilinc)
275 dirtcnt = 0;
276}
277
278tflush()
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
d4a8288f
MH
289/*
290 * Synchronize the state of the temporary file in case
291 * a crash occurs.
292 */
293synctmp()
294{
295 register int cnt;
296 register line *a;
297 register short *bp;
298
7c4625ef
MH
299#ifdef VMUNIX
300 if (stilinc)
301 return;
302#endif
d4a8288f
MH
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);
d266c416
MH
320 if (*bp > NMBLKS)
321 error(" Tmp file too large");
d4a8288f
MH
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) {
331oops:
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;
a7a51e4a
SL
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 */
5a6c967e 348#ifndef vms
a7a51e4a
SL
349 (void) fsync(tfile);
350#endif
5a6c967e 351#endif
d4a8288f
MH
352}
353
354TSYNC()
355{
356
299f2784 357 if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */
7c4625ef
MH
358#ifdef VMUNIX
359 if (stilinc)
360 tflush();
361#endif
d4a8288f
MH
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 */
383struct 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
390struct rbuf {
391 short rb_prev;
392 short rb_next;
393 char rb_text[BUFSIZ - 2 * sizeof (short)];
3c7b865a 394} *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf;
887e3e0d
MH
395#ifdef VMUNIX
396short rused[256];
397#else
d4a8288f 398short rused[32];
887e3e0d 399#endif
d4a8288f
MH
400short rnleft;
401short rblock;
402short rnext;
403char *rbufcp;
404
405regio(b, iofcn)
406 short b;
407 int (*iofcn)();
408{
409
410 if (rfile == -1) {
411 CP(rfname, tfname);
5a6c967e 412 *(strend(rfname) - EPOSITION) = 'R';
d4a8288f
MH
413 rfile = creat(rfname, 0600);
414 if (rfile < 0)
415oops:
416 filioerr(rfname);
5a6c967e
CH
417 else
418 close(rfile);
d4a8288f
MH
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
429REGblk()
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
5a6c967e 443 ex_printf("allocating block %d\n", i * 16 + j);
d4a8288f
MH
444#endif
445 return (i * 16 + j);
446 }
447 }
448 error("Out of register space (ugh)");
449 /*NOTREACHED*/
450}
451
452struct strreg *
453mapreg(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
462int shread();
463
464KILLreg(c)
465 register int c;
466{
d4a8288f
MH
467 register struct strreg *sp;
468
3c7b865a 469 rbuf = &KILLrbuf;
d4a8288f
MH
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
5a6c967e 476 ex_printf("freeing block %d\n", rblock);
d4a8288f
MH
477#endif
478 rused[rblock / 16] &= ~(1 << (rblock % 16));
479 regio(rblock, shread);
480 rblock = rbuf->rb_next;
481 }
482}
483
484/*VARARGS*/
485shread()
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
494int getREG();
495
496putreg(c)
497 char c;
498{
d4a8288f
MH
499 register line *odot = dot;
500 register line *odol = dol;
501 register int cnt;
502
503 deletenone();
504 appendnone();
3c7b865a 505 rbuf = &putrbuf;
d4a8288f
MH
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)) {
887e3e0d
MH
519 if (!FIXUNDO) {
520 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
521 error("Can't put partial line inside macro");
522 }
d4a8288f
MH
523 squish();
524 addr1 = addr2 = dol;
525 }
887e3e0d 526 cnt = append(getREG, addr2);
d4a8288f
MH
527 if (inopen && partreg(c)) {
528 unddol = dol;
529 dol = odol;
530 dot = odot;
531 pragged(0);
532 }
d4a8288f
MH
533 killcnt(cnt);
534 notecnt = cnt;
535}
536
537partreg(c)
538 char c;
539{
540
541 return (mapreg(c)->rg_flags);
542}
543
544notpart(c)
545 register int c;
546{
547
548 if (c)
549 mapreg(c)->rg_flags = 0;
550}
551
552getREG()
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
578YANKreg(c)
579 register int c;
580{
d4a8288f
MH
581 register line *addr;
582 register struct strreg *sp;
f0f2d980 583 char savelb[LBSIZE];
d4a8288f
MH
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;
3c7b865a 591 rbuf = &YANKrbuf;
d4a8288f
MH
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 }
f0f2d980 600 CP(savelb,linebuf);
d4a8288f
MH
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();
f0f2d980 613 CP(linebuf,savelb);
d4a8288f
MH
614}
615
616kshift()
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
625YANKline()
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
651rbflush()
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 */
665regbuf(c, buf, buflen)
666char c;
667char *buf;
668int buflen;
669{
d4a8288f
MH
670 register char *p, *lp;
671
3c7b865a 672 rbuf = &regrbuf;
d4a8288f
MH
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}
d266c416
MH
693
694/*
695 * Encryption routines. These are essentially unmodified from ed.
696 */
697