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