Annotation of src/usr.bin/mg/buffer.c, Revision 1.2
1.1 deraadt 1: /*
2: * Buffer handling.
3: */
4: #include "def.h"
5: #include "kbd.h" /* needed for modes */
6:
7: static RSIZE itor();
8:
9: /*
10: * Attach a buffer to a window. The values of dot and mark come
11: * from the buffer if the use count is 0. Otherwise, they come
12: * from some other window. *scratch* is the default alternate
13: * buffer.
14: */
15: /*ARGSUSED*/
16: usebuffer(f, n)
17: {
18: register BUFFER *bp;
19: register int s;
20: char bufn[NBUFN];
21:
22: /* Get buffer to use from user */
23: if ((curbp->b_altb == NULL)
24: && ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
25: s=eread("Switch to buffer: ", bufn, NBUFN, EFNEW|EFBUF);
26: else
27: s=eread("Switch to buffer: (default %s) ", bufn, NBUFN,
28: EFNEW|EFBUF, curbp->b_altb->b_bname);
29:
30: if (s == ABORT) return s;
31: if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb ;
32: else if ((bp=bfind(bufn, TRUE)) == NULL) return FALSE;
33:
34: /* and put it in current window */
35: curbp = bp;
36: return showbuffer(bp, curwp, WFFORCE|WFHARD);
37: }
38:
39: /*
40: * pop to buffer asked for by the user.
41: */
42: /*ARGSUSED*/
43: poptobuffer(f, n)
44: {
45: register BUFFER *bp;
1.2 ! millert 46: register MGWIN *wp;
1.1 deraadt 47: register int s;
48: char bufn[NBUFN];
1.2 ! millert 49: MGWIN *popbuf();
1.1 deraadt 50:
51: /* Get buffer to use from user */
52: if ((curbp->b_altb == NULL)
53: && ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
54: s=eread("Switch to buffer in other window: ", bufn, NBUFN,
55: EFNEW|EFBUF);
56: else
57: s=eread("Switch to buffer in other window: (default %s) ",
58: bufn, NBUFN, EFNEW|EFBUF, curbp->b_altb->b_bname);
59: if (s == ABORT) return s;
60: if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb ;
61: else if ((bp=bfind(bufn, TRUE)) == NULL) return FALSE;
62:
63: /* and put it in a new window */
64: if ((wp = popbuf(bp)) == NULL) return FALSE;
65: curbp = bp;
66: curwp = wp;
67: return TRUE;
68: }
69:
70: /*
71: * Dispose of a buffer, by name.
72: * Ask for the name. Look it up (don't get too
73: * upset if it isn't there at all!). Clear the buffer (ask
74: * if the buffer has been changed). Then free the header
75: * line and the buffer header. Bound to "C-X K".
76: */
77: /*ARGSUSED*/
78: killbuffer(f, n)
79: {
80: register BUFFER *bp;
81: register BUFFER *bp1;
82: register BUFFER *bp2;
1.2 ! millert 83: MGWIN *wp;
1.1 deraadt 84: register int s;
85: char bufn[NBUFN];
86:
87: if ((s=eread("Kill buffer: (default %s) ", bufn, NBUFN, EFNEW|EFBUF,
88: curbp->b_bname)) == ABORT) return (s);
89: else if (s == FALSE) bp = curbp;
90: else if ((bp=bfind(bufn, FALSE)) == NULL) return FALSE;
91:
92: /* find some other buffer to display. try the alternate buffer,
93: * then the first different buffer in the buffer list. if
94: * there's only one buffer, create buffer *scratch* and make
95: * it the alternate buffer. return if *scratch* is only buffer
96: */
97: if ((bp1 = bp->b_altb) == NULL) {
98: bp1 = (bp == bheadp) ? bp->b_bufp : bheadp;
99: if (bp1 == NULL) {
100: /* only one buffer. see if it's *scratch* */
101: if (bp == bfind("*scratch*",FALSE))
102: return FALSE;
103: /* create *scratch* for alternate buffer */
104: if ((bp1 = bfind("*scratch*",TRUE)) == NULL)
105: return FALSE;
106: }
107: }
108: if (bclear(bp) != TRUE) return TRUE;
109: for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp) {
110: if (wp->w_bufp == bp) {
111: bp2 = bp1->b_altb; /* save alternate buffer */
112: if(showbuffer(bp1, wp, WFMODE|WFFORCE|WFHARD) != NULL)
113: bp1->b_altb = bp2;
114: else bp1 = bp2;
115: }
116: }
117: if (bp == curbp) curbp = bp1;
118: free((char *) bp->b_linep); /* Release header line. */
119: bp2 = NULL; /* Find the header. */
120: bp1 = bheadp;
121: while (bp1 != bp) {
122: if (bp1->b_altb == bp)
123: bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb;
124: bp2 = bp1;
125: bp1 = bp1->b_bufp;
126: }
127: bp1 = bp1->b_bufp; /* Next one in chain. */
128: if (bp2 == NULL) /* Unlink it. */
129: bheadp = bp1;
130: else
131: bp2->b_bufp = bp1;
132: while (bp1 != NULL) { /* Finish with altb's */
133: if (bp1->b_altb == bp)
134: bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb;
135: bp1 = bp1->b_bufp;
136: }
137: free(bp->b_bname); /* Release name block */
138: free((char *) bp); /* Release buffer block */
139: return TRUE;
140: }
141:
142: /*
143: * Save some buffers - just call anycb with the arg flag.
144: */
145: /*ARGSUSED*/
146: savebuffers(f, n)
147: {
148: if (anycb(f) == ABORT) return ABORT;
149: return TRUE;
150: }
151:
152: /*
153: * Display the buffer list. This is done
154: * in two parts. The "makelist" routine figures out
155: * the text, and puts it in a buffer. "popbuf"
156: * then pops the data onto the screen. Bound to
157: * "C-X C-B".
158: */
159: /*ARGSUSED*/
160: listbuffers(f, n)
161: {
162: register BUFFER *bp;
1.2 ! millert 163: register MGWIN *wp;
1.1 deraadt 164: BUFFER *makelist();
1.2 ! millert 165: MGWIN *popbuf();
1.1 deraadt 166:
167: if ((bp=makelist()) == NULL || (wp=popbuf(bp)) == NULL)
168: return FALSE;
169: wp->w_dotp = bp->b_dotp; /* fix up if window already on screen */
170: wp->w_doto = bp->b_doto;
171: return TRUE;
172: }
173:
174: /*
175: * This routine rebuilds the text for the
176: * list buffers command. Return TRUE if
177: * everything works. Return FALSE if there
178: * is an error (if there is no memory).
179: */
180: BUFFER *
181: makelist() {
182: register char *cp1;
183: register char *cp2;
184: register int c;
185: register BUFFER *bp;
186: LINE *lp;
187: register RSIZE nbytes;
188: BUFFER *blp;
189: char b[6+1];
190: char line[128];
191:
192: if ((blp = bfind("*Buffer List*", TRUE)) == NULL) return NULL;
193: if (bclear(blp) != TRUE) return NULL;
194: blp->b_flag &= ~BFCHG; /* Blow away old. */
195:
196: (VOID) strcpy(line, " MR Buffer");
197: cp1 = line + 10;
198: while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
199: (VOID) strcpy(cp1, "Size File");
200: if (addline(blp, line) == FALSE) return NULL;
201: (VOID) strcpy(line, " -- ------");
202: cp1 = line + 10;
203: while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
204: (VOID) strcpy(cp1, "---- ----");
205: if (addline(blp, line) == FALSE) return NULL;
206: bp = bheadp; /* For all buffers */
207: while (bp != NULL) {
208: cp1 = &line[0]; /* Start at left edge */
209: *cp1++ = (bp == curbp) ? '.' : ' ';
210: *cp1++ = ((bp->b_flag&BFCHG) != 0) ? '*' : ' ';
211: *cp1++ = ' '; /* Gap. */
212: *cp1++ = ' ';
213: cp2 = &bp->b_bname[0]; /* Buffer name */
214: while ((c = *cp2++) != 0)
215: *cp1++ = c;
216: while (cp1 < &line[4+NBUFN+1])
217: *cp1++ = ' ';
218: nbytes = 0; /* Count bytes in buf. */
219: if (bp != blp) {
220: lp = lforw(bp->b_linep);
221: while (lp != bp->b_linep) {
222: nbytes += llength(lp)+1;
223: lp = lforw(lp);
224: }
225: if(nbytes) nbytes--; /* no bonus newline */
226: }
227: (VOID) itor(b, 6, nbytes); /* 6 digit buffer size. */
228: cp2 = &b[0];
229: while ((c = *cp2++) != 0)
230: *cp1++ = c;
231: *cp1++ = ' '; /* Gap.. */
232: cp2 = &bp->b_fname[0]; /* File name */
233: if (*cp2 != 0) {
234: while ((c = *cp2++) != 0) {
235: if (cp1 < &line[128-1])
236: *cp1++ = c;
237: }
238: }
239: *cp1 = 0; /* Add to the buffer. */
240: if (addline(blp, line) == FALSE)
241: return NULL;
242: bp = bp->b_bufp;
243: }
244: blp->b_dotp = lforw(blp->b_linep); /* put dot at beginning of buffer */
245: blp->b_doto = 0;
246: return blp; /* All done */
247: }
248:
249: /*
250: * Used above.
251: */
252: static RSIZE itor(buf, width, num)
253: register char buf[]; register int width; register RSIZE num; {
254: register RSIZE r;
255:
256: if (num / 10 == 0) {
257: buf[0] = (num % 10) + '0';
258: for (r = 1; r < width; buf[r++] = ' ')
259: ;
260: buf[width] = '\0';
261: return 1;
262: } else {
263: buf[r = itor(buf, width, num / (RSIZE)10)] =
264: (num % (RSIZE)10) + '0';
265: return r + 1;
266: }
267: /*NOTREACHED*/
268: }
269:
270: /*
271: * The argument "text" points to
272: * a string. Append this line to the
273: * buffer. Handcraft the EOL
274: * on the end. Return TRUE if it worked and
275: * FALSE if you ran out of room.
276: */
277: addline(bp, text) register BUFFER *bp; char *text; {
278: register LINE *lp;
279: register int i;
280: register int ntext;
281:
282: ntext = strlen(text);
283: if ((lp=lalloc(ntext)) == NULL)
284: return FALSE;
285: for (i=0; i<ntext; ++i)
286: lputc(lp, i, text[i]);
287: bp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
288: lp->l_bp = bp->b_linep->l_bp;
289: bp->b_linep->l_bp = lp;
290: lp->l_fp = bp->b_linep;
291: #ifdef CANTHAPPEN
292: if (bp->b_dotp == bp->b_linep) /* If "." is at the end */
293: bp->b_dotp = lp; /* move it to new line */
294: if (bp->b_markp == bp->b_linep) /* ditto for mark */
295: bp->b_markp = lp;
296: #endif
297: return TRUE;
298: }
299:
300: /*
301: * Look through the list of buffers, giving the user
302: * a chance to save them. Return TRUE if there are
303: * any changed buffers afterwards. Buffers that don't
304: * have an associated file don't count. Return FALSE
305: * if there are no changed buffers.
306: */
307: anycb(f) {
308: register BUFFER *bp;
309: register int s = FALSE, save = FALSE;
310: char prompt[NFILEN + 11];
311: VOID upmodes();
312:
313: for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
314: if (*(bp->b_fname) != '\0'
315: && (bp->b_flag&BFCHG) != 0) {
316: (VOID) strcpy(prompt, "Save file ");
317: (VOID) strcpy(prompt + 10, bp->b_fname);
318: if ((f == TRUE || (save = eyorn(prompt)) == TRUE)
319: && buffsave(bp) == TRUE) {
320: bp->b_flag &= ~BFCHG;
321: upmodes(bp);
322: } else s = TRUE;
323: if (save == ABORT) return (save);
324: save = TRUE;
325: }
326: }
327: if (save == FALSE /* && kbdmop == NULL */ ) /* experimental */
328: ewprintf("(No files need saving)");
329: return s;
330: }
331:
332: /*
333: * Search for a buffer, by name.
334: * If not found, and the "cflag" is TRUE,
335: * create a buffer and put it in the list of
336: * all buffers. Return pointer to the BUFFER
337: * block for the buffer.
338: */
339: BUFFER *
340: bfind(bname, cflag) register char *bname; {
341: register BUFFER *bp;
342: char *malloc();
343: register LINE *lp;
344: int i;
345: extern int defb_nmodes;
346: extern MAPS *defb_modes[PBMODES];
347: extern int defb_flag;
348:
349: bp = bheadp;
350: while (bp != NULL) {
351: if (fncmp(bname, bp->b_bname) == 0)
352: return bp;
353: bp = bp->b_bufp;
354: }
355: if (cflag!=TRUE) return NULL;
356: /*NOSTRICT*/
357: if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) {
358: ewprintf("Can't get %d bytes", sizeof(BUFFER));
359: return NULL;
360: }
361: if ((bp->b_bname=malloc((unsigned)(strlen(bname)+1))) == NULL) {
362: ewprintf("Can't get %d bytes", strlen(bname)+1);
363: free((char *) bp);
364: return NULL;
365: }
366: if ((lp = lalloc(0)) == NULL) {
367: free(bp->b_bname);
368: free((char *) bp);
369: return NULL;
370: }
371: bp->b_altb = bp->b_bufp = NULL;
372: bp->b_dotp = lp;
373: bp->b_doto = 0;
374: bp->b_markp = NULL;
375: bp->b_marko = 0;
376: bp->b_flag = defb_flag;
377: bp->b_nwnd = 0;
378: bp->b_linep = lp;
379: bp->b_nmodes = defb_nmodes;
380: i = 0;
381: do {
382: bp->b_modes[i] = defb_modes[i];
383: } while(i++ < defb_nmodes);
384: bp->b_fname[0] = '\0';
385: bzero(&bp->b_fi, sizeof(bp->b_fi));
386: (VOID) strcpy(bp->b_bname, bname);
387: lp->l_fp = lp;
388: lp->l_bp = lp;
389: bp->b_bufp = bheadp;
390: bheadp = bp;
391: return bp;
392: }
393:
394: /*
395: * This routine blows away all of the text
396: * in a buffer. If the buffer is marked as changed
397: * then we ask if it is ok to blow it away; this is
398: * to save the user the grief of losing text. The
399: * window chain is nearly always wrong if this gets
400: * called; the caller must arrange for the updates
401: * that are required. Return TRUE if everything
402: * looks good.
403: */
404: bclear(bp) register BUFFER *bp; {
405: register LINE *lp;
406: register int s;
407: VOID lfree();
408:
409: if ((bp->b_flag&BFCHG) != 0 /* Changed. */
410: && (s=eyesno("Buffer modified; kill anyway")) != TRUE)
411: return (s);
412: bp->b_flag &= ~BFCHG; /* Not changed */
413: while ((lp=lforw(bp->b_linep)) != bp->b_linep)
414: lfree(lp);
415: bp->b_dotp = bp->b_linep; /* Fix "." */
416: bp->b_doto = 0;
417: bp->b_markp = NULL; /* Invalidate "mark" */
418: bp->b_marko = 0;
419: return TRUE;
420: }
421:
422: /*
423: * Display the given buffer in the given window. Flags indicated
424: * action on redisplay.
425: */
1.2 ! millert 426: showbuffer(bp, wp, flags) register BUFFER *bp; register MGWIN *wp; {
1.1 deraadt 427: register BUFFER *obp;
1.2 ! millert 428: MGWIN *owp;
1.1 deraadt 429:
430: if (wp->w_bufp == bp) { /* Easy case! */
431: wp->w_flag |= flags;
432: return TRUE;
433: }
434:
435: /* First, dettach the old buffer from the window */
436: if ((bp->b_altb = obp = wp->w_bufp) != NULL) {
437: if (--obp->b_nwnd == 0) {
438: obp->b_dotp = wp->w_dotp;
439: obp->b_doto = wp->w_doto;
440: obp->b_markp = wp->w_markp;
441: obp->b_marko = wp->w_marko;
442: }
443: }
444:
445: /* Now, attach the new buffer to the window */
446: wp->w_bufp = bp;
447:
448: if (bp->b_nwnd++ == 0) { /* First use. */
449: wp->w_dotp = bp->b_dotp;
450: wp->w_doto = bp->b_doto;
451: wp->w_markp = bp->b_markp;
452: wp->w_marko = bp->b_marko;
453: } else
454: /* already on screen, steal values from other window */
455: for (owp = wheadp; owp != NULL; owp = wp->w_wndp)
456: if (wp->w_bufp == bp && owp != wp) {
457: wp->w_dotp = owp->w_dotp;
458: wp->w_doto = owp->w_doto;
459: wp->w_markp = owp->w_markp;
460: wp->w_marko = owp->w_marko;
461: break;
462: }
463: wp->w_flag |= WFMODE|flags;
464: return TRUE;
465: }
466:
467: /*
468: * Pop the buffer we got passed onto the screen.
469: * Returns a status.
470: */
1.2 ! millert 471: MGWIN *
1.1 deraadt 472: popbuf(bp) register BUFFER *bp; {
1.2 ! millert 473: register MGWIN *wp;
1.1 deraadt 474:
475: if (bp->b_nwnd == 0) { /* Not on screen yet. */
476: if ((wp=wpopup()) == NULL) return NULL;
477: } else
478: for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
479: if (wp->w_bufp == bp) {
480: wp->w_flag |= WFHARD|WFFORCE;
481: return wp ;
482: }
483: if (showbuffer(bp, wp, WFHARD) != TRUE) return NULL;
484: return wp;
485: }
486:
487: /*
488: * Insert another buffer at dot. Very useful.
489: */
490: /*ARGSUSED*/
491: bufferinsert(f, n)
492: {
493: register BUFFER *bp;
494: register LINE *clp;
495: register int clo;
496: register int nline;
497: int s;
498: char bufn[NBUFN];
499:
500: /* Get buffer to use from user */
501: if (curbp->b_altb != NULL)
502: s=eread("Insert buffer: (default %s) ", bufn, NBUFN,
503: EFNEW|EFBUF, &(curbp->b_altb->b_bname),
504: (char *) NULL) ;
505: else
506: s=eread("Insert buffer: ", bufn, NBUFN, EFNEW|EFBUF,
507: (char *) NULL) ;
508: if (s == ABORT) return (s);
509: if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb;
510: else if ((bp=bfind(bufn, FALSE)) == NULL) return FALSE;
511:
512: if (bp==curbp) {
513: ewprintf("Cannot insert buffer into self");
514: return FALSE;
515: }
516:
517: /* insert the buffer */
518: nline = 0;
519: clp = lforw(bp->b_linep);
520: for(;;) {
521: for (clo = 0; clo < llength(clp); clo++)
522: if (linsert(1, lgetc(clp, clo)) == FALSE)
523: return FALSE;
524: if((clp = lforw(clp)) == bp->b_linep) break;
525: if (newline(FFRAND, 1) == FALSE) /* fake newline */
526: return FALSE;
527: nline++;
528: }
529: if (nline == 1) ewprintf("[Inserted 1 line]");
530: else ewprintf("[Inserted %d lines]", nline);
531:
532: clp = curwp->w_linep; /* cosmetic adjustment */
533: if (curwp->w_dotp == clp) { /* for offscreen insert */
534: while (nline-- && lback(clp)!=curbp->b_linep)
535: clp = lback(clp);
536: curwp->w_linep = clp; /* adjust framing. */
537: curwp->w_flag |= WFHARD;
538: }
539: return (TRUE);
540: }
541:
542: /*
543: * Turn off the dirty bit on this buffer.
544: */
545: /*ARGSUSED*/
546: notmodified(f, n)
547: {
1.2 ! millert 548: register MGWIN *wp;
1.1 deraadt 549:
550: curbp->b_flag &= ~BFCHG;
551: wp = wheadp; /* Update mode lines. */
552: while (wp != NULL) {
553: if (wp->w_bufp == curbp)
554: wp->w_flag |= WFMODE;
555: wp = wp->w_wndp;
556: }
557: ewprintf("Modification-flag cleared");
558: return TRUE;
559: }
560:
561: #ifndef NO_HELP
562: /*
563: * Popbuf and set all windows to top of buffer. Currently only used by
564: * help functions.
565: */
566:
567: popbuftop(bp)
568: register BUFFER *bp;
569: {
1.2 ! millert 570: register MGWIN *wp;
1.1 deraadt 571:
572: bp->b_dotp = lforw(bp->b_linep);
573: bp->b_doto = 0;
574: if(bp->b_nwnd != 0) {
575: for(wp = wheadp; wp!=NULL; wp = wp->w_wndp)
576: if(wp->w_bufp == bp) {
577: wp->w_dotp = bp->b_dotp;
578: wp->w_doto = 0;
579: wp->w_flag |= WFHARD;
580: }
581: }
582: return popbuf(bp) != NULL;
583: }
584: #endif