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