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