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