cleanups, add manual page
[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
7bcb0072 8static char *sccsid = "@(#)ex_temp.c 7.6.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
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;
186
187 bno = (atl >> OFFBTS) & BLKMSK;
188 off = (atl << SHFT) & LBTMSK;
189 if (bno >= NMBLKS)
190 error(" Tmp file too large");
191 nleft = BUFSIZ - off;
192 if (bno == iblock) {
193 ichanged |= iof;
194 hitin2 = 0;
195 return (ibuff + off);
196 }
197 if (bno == iblock2) {
198 ichang2 |= iof;
199 hitin2 = 1;
200 return (ibuff2 + off);
201 }
202 if (bno == oblock)
203 return (obuff + off);
204 if (iof == READ) {
205 if (hitin2 == 0) {
d266c416 206 if (ichang2) {
d4a8288f 207 blkio(iblock2, ibuff2, write);
d266c416 208 }
d4a8288f
MH
209 ichang2 = 0;
210 iblock2 = bno;
211 blkio(bno, ibuff2, read);
212 hitin2 = 1;
213 return (ibuff2 + off);
214 }
215 hitin2 = 0;
d266c416 216 if (ichanged) {
d4a8288f 217 blkio(iblock, ibuff, write);
d266c416 218 }
d4a8288f
MH
219 ichanged = 0;
220 iblock = bno;
221 blkio(bno, ibuff, read);
222 return (ibuff + off);
223 }
d266c416 224 if (oblock >= 0) {
d266c416
MH
225 blkio(oblock, obuff, write);
226 }
d4a8288f
MH
227 oblock = bno;
228 return (obuff + off);
229}
230
7c4625ef 231#ifdef VMUNIX
5a6c967e
CH
232#ifdef vms
233#define INCORB 32
234#else
7c4625ef 235#define INCORB 64
5a6c967e 236#endif
7c4625ef
MH
237char incorb[INCORB+1][BUFSIZ];
238#define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1)))
239int stilinc; /* up to here not written yet */
240#endif
241
d4a8288f
MH
242blkio(b, buf, iofcn)
243 short b;
244 char *buf;
245 int (*iofcn)();
246{
247
7c4625ef
MH
248#ifdef VMUNIX
249 if (b < INCORB) {
250 if (iofcn == read) {
251 bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ);
252 return;
253 }
254 bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ);
255 if (laste) {
256 if (b >= stilinc)
257 stilinc = b + 1;
258 return;
259 }
260 } else if (stilinc)
261 tflush();
262#endif
d4a8288f
MH
263 lseek(tfile, (long) (unsigned) b * BUFSIZ, 0);
264 if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
265 filioerr(tfname);
266}
267
7c4625ef
MH
268#ifdef VMUNIX
269tlaste()
270{
271
272 if (stilinc)
273 dirtcnt = 0;
274}
275
276tflush()
277{
278 int i = stilinc;
279
280 stilinc = 0;
281 lseek(tfile, (long) 0, 0);
282 if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ))
283 filioerr(tfname);
284}
285#endif
286
d4a8288f
MH
287/*
288 * Synchronize the state of the temporary file in case
289 * a crash occurs.
290 */
291synctmp()
292{
293 register int cnt;
294 register line *a;
295 register short *bp;
296
7c4625ef
MH
297#ifdef VMUNIX
298 if (stilinc)
299 return;
300#endif
d4a8288f
MH
301 if (dol == zero)
302 return;
303 if (ichanged)
304 blkio(iblock, ibuff, write);
305 ichanged = 0;
306 if (ichang2)
307 blkio(iblock2, ibuff2, write);
308 ichang2 = 0;
309 if (oblock != -1)
310 blkio(oblock, obuff, write);
311 time(&H.Time);
312 uid = getuid();
313 *zero = (line) H.Time;
314 for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) {
315 if (*bp < 0) {
316 tline = (tline + OFFMSK) &~ OFFMSK;
317 *bp = ((tline >> OFFBTS) & BLKMSK);
d266c416
MH
318 if (*bp > NMBLKS)
319 error(" Tmp file too large");
d4a8288f
MH
320 tline += INCRMT;
321 oblock = *bp + 1;
322 bp[1] = -1;
323 }
324 lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0);
325 cnt = ((dol - a) + 2) * sizeof (line);
326 if (cnt > BUFSIZ)
327 cnt = BUFSIZ;
328 if (write(tfile, (char *) a, cnt) != cnt) {
329oops:
330 *zero = 0;
331 filioerr(tfname);
332 }
333 *zero = 0;
334 }
335 flines = lineDOL();
336 lseek(tfile, 0l, 0);
337 if (write(tfile, (char *) &H, sizeof H) != sizeof H)
338 goto oops;
a7a51e4a
SL
339#ifdef notdef
340 /*
341 * This will insure that exrecover gets as much
342 * back after a crash as is absolutely possible,
343 * but can result in pregnant pauses between commands
344 * when the TSYNC call is made, so...
345 */
5a6c967e 346#ifndef vms
a7a51e4a
SL
347 (void) fsync(tfile);
348#endif
5a6c967e 349#endif
d4a8288f
MH
350}
351
352TSYNC()
353{
354
299f2784 355 if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */
7c4625ef
MH
356#ifdef VMUNIX
357 if (stilinc)
358 tflush();
359#endif
d4a8288f
MH
360 dirtcnt = 0;
361 synctmp();
362 }
363}
364
365/*
366 * Named buffer routines.
367 * These are implemented differently than the main buffer.
368 * Each named buffer has a chain of blocks in the register file.
369 * Each block contains roughly 508 chars of text,
370 * and a previous and next block number. We also have information
371 * about which blocks came from deletes of multiple partial lines,
372 * e.g. deleting a sentence or a LISP object.
373 *
374 * We maintain a free map for the temp file. To free the blocks
375 * in a register we must read the blocks to find how they are chained
376 * together.
377 *
378 * BUG: The default savind of deleted lines in numbered
379 * buffers may be rather inefficient; it hasn't been profiled.
380 */
381struct strreg {
382 short rg_flags;
383 short rg_nleft;
384 short rg_first;
385 short rg_last;
386} strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp;
387
388struct rbuf {
389 short rb_prev;
390 short rb_next;
391 char rb_text[BUFSIZ - 2 * sizeof (short)];
3c7b865a 392} *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf;
887e3e0d
MH
393#ifdef VMUNIX
394short rused[256];
395#else
d4a8288f 396short rused[32];
887e3e0d 397#endif
d4a8288f
MH
398short rnleft;
399short rblock;
400short rnext;
401char *rbufcp;
402
403regio(b, iofcn)
404 short b;
405 int (*iofcn)();
406{
407
408 if (rfile == -1) {
409 CP(rfname, tfname);
5a6c967e 410 *(strend(rfname) - EPOSITION) = 'R';
d4a8288f
MH
411 rfile = creat(rfname, 0600);
412 if (rfile < 0)
413oops:
414 filioerr(rfname);
5a6c967e
CH
415 else
416 close(rfile);
d4a8288f
MH
417 rfile = open(rfname, 2);
418 if (rfile < 0)
419 goto oops;
420 }
421 lseek(rfile, (long) b * BUFSIZ, 0);
422 if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ)
423 goto oops;
424 rblock = b;
425}
426
427REGblk()
428{
429 register int i, j, m;
430
431 for (i = 0; i < sizeof rused / sizeof rused[0]; i++) {
432 m = (rused[i] ^ 0177777) & 0177777;
433 if (i == 0)
434 m &= ~1;
435 if (m != 0) {
436 j = 0;
437 while ((m & 1) == 0)
438 j++, m >>= 1;
439 rused[i] |= (1 << j);
440#ifdef RDEBUG
5a6c967e 441 ex_printf("allocating block %d\n", i * 16 + j);
d4a8288f
MH
442#endif
443 return (i * 16 + j);
444 }
445 }
446 error("Out of register space (ugh)");
447 /*NOTREACHED*/
448}
449
450struct strreg *
451mapreg(c)
452 register int c;
453{
454
455 if (isupper(c))
456 c = tolower(c);
457 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
458}
459
460int shread();
461
462KILLreg(c)
463 register int c;
464{
d4a8288f
MH
465 register struct strreg *sp;
466
3c7b865a 467 rbuf = &KILLrbuf;
d4a8288f
MH
468 sp = mapreg(c);
469 rblock = sp->rg_first;
470 sp->rg_first = sp->rg_last = 0;
471 sp->rg_flags = sp->rg_nleft = 0;
472 while (rblock != 0) {
473#ifdef RDEBUG
5a6c967e 474 ex_printf("freeing block %d\n", rblock);
d4a8288f
MH
475#endif
476 rused[rblock / 16] &= ~(1 << (rblock % 16));
477 regio(rblock, shread);
478 rblock = rbuf->rb_next;
479 }
480}
481
482/*VARARGS*/
483shread()
484{
485 struct front { short a; short b; };
486
487 if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front))
488 return (sizeof (struct rbuf));
489 return (0);
490}
491
492int getREG();
493
494putreg(c)
495 char c;
496{
d4a8288f
MH
497 register line *odot = dot;
498 register line *odol = dol;
499 register int cnt;
500
501 deletenone();
502 appendnone();
3c7b865a 503 rbuf = &putrbuf;
d4a8288f
MH
504 rnleft = 0;
505 rblock = 0;
506 rnext = mapreg(c)->rg_first;
507 if (rnext == 0) {
508 if (inopen) {
509 splitw++;
510 vclean();
511 vgoto(WECHO, 0);
512 }
513 vreg = -1;
514 error("Nothing in register %c", c);
515 }
516 if (inopen && partreg(c)) {
887e3e0d
MH
517 if (!FIXUNDO) {
518 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
519 error("Can't put partial line inside macro");
520 }
d4a8288f
MH
521 squish();
522 addr1 = addr2 = dol;
523 }
887e3e0d 524 cnt = append(getREG, addr2);
d4a8288f
MH
525 if (inopen && partreg(c)) {
526 unddol = dol;
527 dol = odol;
528 dot = odot;
529 pragged(0);
530 }
d4a8288f
MH
531 killcnt(cnt);
532 notecnt = cnt;
533}
534
535partreg(c)
536 char c;
537{
538
539 return (mapreg(c)->rg_flags);
540}
541
542notpart(c)
543 register int c;
544{
545
546 if (c)
547 mapreg(c)->rg_flags = 0;
548}
549
550getREG()
551{
552 register char *lp = linebuf;
553 register int c;
554
555 for (;;) {
556 if (rnleft == 0) {
557 if (rnext == 0)
558 return (EOF);
559 regio(rnext, read);
560 rnext = rbuf->rb_next;
561 rbufcp = rbuf->rb_text;
562 rnleft = sizeof rbuf->rb_text;
563 }
564 c = *rbufcp;
565 if (c == 0)
566 return (EOF);
567 rbufcp++, --rnleft;
568 if (c == '\n') {
569 *lp++ = 0;
570 return (0);
571 }
572 *lp++ = c;
573 }
574}
575
576YANKreg(c)
577 register int c;
578{
d4a8288f
MH
579 register line *addr;
580 register struct strreg *sp;
f0f2d980 581 char savelb[LBSIZE];
d4a8288f
MH
582
583 if (isdigit(c))
584 kshift();
585 if (islower(c))
586 KILLreg(c);
587 strp = sp = mapreg(c);
588 sp->rg_flags = inopen && cursor && wcursor;
3c7b865a 589 rbuf = &YANKrbuf;
d4a8288f
MH
590 if (sp->rg_last) {
591 regio(sp->rg_last, read);
592 rnleft = sp->rg_nleft;
593 rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
594 } else {
595 rblock = 0;
596 rnleft = 0;
597 }
f0f2d980 598 CP(savelb,linebuf);
d4a8288f
MH
599 for (addr = addr1; addr <= addr2; addr++) {
600 getline(*addr);
601 if (sp->rg_flags) {
602 if (addr == addr2)
603 *wcursor = 0;
604 if (addr == addr1)
605 strcpy(linebuf, cursor);
606 }
607 YANKline();
608 }
609 rbflush();
610 killed();
f0f2d980 611 CP(linebuf,savelb);
d4a8288f
MH
612}
613
614kshift()
615{
616 register int i;
617
618 KILLreg('9');
619 for (i = '8'; i >= '0'; i--)
620 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
621}
622
623YANKline()
624{
625 register char *lp = linebuf;
626 register struct rbuf *rp = rbuf;
627 register int c;
628
629 do {
630 c = *lp++;
631 if (c == 0)
632 c = '\n';
633 if (rnleft == 0) {
634 rp->rb_next = REGblk();
635 rbflush();
636 rblock = rp->rb_next;
637 rp->rb_next = 0;
638 rp->rb_prev = rblock;
639 rnleft = sizeof rp->rb_text;
640 rbufcp = rp->rb_text;
641 }
642 *rbufcp++ = c;
643 --rnleft;
644 } while (c != '\n');
645 if (rnleft)
646 *rbufcp = 0;
647}
648
649rbflush()
650{
651 register struct strreg *sp = strp;
652
653 if (rblock == 0)
654 return;
655 regio(rblock, write);
656 if (sp->rg_first == 0)
657 sp->rg_first = rblock;
658 sp->rg_last = rblock;
659 sp->rg_nleft = rnleft;
660}
661
662/* Register c to char buffer buf of size buflen */
663regbuf(c, buf, buflen)
664char c;
665char *buf;
666int buflen;
667{
d4a8288f
MH
668 register char *p, *lp;
669
3c7b865a 670 rbuf = &regrbuf;
d4a8288f
MH
671 rnleft = 0;
672 rblock = 0;
673 rnext = mapreg(c)->rg_first;
674 if (rnext==0) {
675 *buf = 0;
676 error("Nothing in register %c",c);
677 }
678 p = buf;
679 while (getREG()==0) {
680 for (lp=linebuf; *lp;) {
681 if (p >= &buf[buflen])
682 error("Register too long@to fit in memory");
683 *p++ = *lp++;
684 }
685 *p++ = '\n';
686 }
687 if (partreg(c)) p--;
688 *p = '\0';
689 getDOT();
690}
d266c416
MH
691
692/*
693 * Encryption routines. These are essentially unmodified from ed.
694 */
695