[BACK]Return to buffer.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/buffer.c, Revision 1.87

1.87    ! florian     1: /*     $OpenBSD: buffer.c,v 1.86 2012/11/03 14:51:41 haesbaert Exp $   */
1.43      kjell       2:
                      3: /* This file is in the public domain. */
1.5       niklas      4:
1.1       deraadt     5: /*
                      6:  *             Buffer handling.
                      7:  */
1.4       millert     8:
1.76      kjell       9: #include "def.h"
                     10: #include "kbd.h"               /* needed for modes */
                     11:
1.56      kjell      12: #include <libgen.h>
                     13: #include <stdarg.h>
1.1       deraadt    14:
1.52      deraadt    15: static struct buffer  *makelist(void);
1.65      kjell      16: static struct buffer *bnew(const char *);
1.75      lum        17:
                     18: static int usebufname(const char *);
1.1       deraadt    19:
1.67      kjell      20: /* Flag for global working dir */
                     21: extern int globalwd;
                     22:
1.50      kjell      23: /* ARGSUSED */
1.27      vincent    24: int
1.31      vincent    25: togglereadonly(int f, int n)
1.27      vincent    26: {
1.68      kjell      27:        int s;
                     28:
                     29:        if ((s = checkdirty(curbp)) != TRUE)
                     30:                return (s);
1.47      kjell      31:        if (!(curbp->b_flag & BFREADONLY))
1.27      vincent    32:                curbp->b_flag |= BFREADONLY;
1.47      kjell      33:        else {
1.68      kjell      34:                curbp->b_flag &= ~BFREADONLY;
1.27      vincent    35:                if (curbp->b_flag & BFCHG)
                     36:                        ewprintf("Warning: Buffer was modified");
                     37:        }
1.70      kjell      38:        curwp->w_rflag |= WFMODE;
1.27      vincent    39:
1.47      kjell      40:        return (TRUE);
1.27      vincent    41: }
                     42:
1.73      deraadt    43: /* Switch to the named buffer.
                     44:  * If no name supplied, switch to the default (alternate) buffer.
                     45:  */
                     46: int
                     47: usebufname(const char *bufp)
                     48: {
                     49:        struct buffer *bp;
                     50:
                     51:        if (bufp == NULL)
                     52:                return (ABORT);
                     53:        if (bufp[0] == '\0' && curbp->b_altb != NULL)
                     54:                bp = curbp->b_altb;
                     55:        else if ((bp = bfind(bufp, TRUE)) == NULL)
                     56:                return (FALSE);
                     57:
                     58:        /* and put it in current window */
                     59:        curbp = bp;
                     60:        return (showbuffer(bp, curwp, WFFRAME | WFFULL));
                     61: }
                     62:
1.1       deraadt    63: /*
                     64:  * Attach a buffer to a window. The values of dot and mark come
                     65:  * from the buffer if the use count is 0. Otherwise, they come
                     66:  * from some other window.  *scratch* is the default alternate
                     67:  * buffer.
                     68:  */
1.3       millert    69: /* ARGSUSED */
                     70: int
1.26      vincent    71: usebuffer(int f, int n)
1.1       deraadt    72: {
1.34      vincent    73:        char    bufn[NBUFN], *bufp;
1.1       deraadt    74:
                     75:        /* Get buffer to use from user */
1.21      deraadt    76:        if ((curbp->b_altb == NULL) &&
                     77:            ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
1.34      vincent    78:                bufp = eread("Switch to buffer: ", bufn, NBUFN, EFNEW | EFBUF);
1.1       deraadt    79:        else
1.34      vincent    80:                bufp = eread("Switch to buffer: (default %s) ", bufn, NBUFN,
1.55      deraadt    81:                    EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname);
1.1       deraadt    82:
1.72      kjell      83:        return (usebufname(bufp));
1.1       deraadt    84: }
                     85:
                     86: /*
                     87:  * pop to buffer asked for by the user.
                     88:  */
1.3       millert    89: /* ARGSUSED */
                     90: int
1.26      vincent    91: poptobuffer(int f, int n)
1.1       deraadt    92: {
1.52      deraadt    93:        struct buffer *bp;
                     94:        struct mgwin  *wp;
1.34      vincent    95:        char    bufn[NBUFN], *bufp;
1.1       deraadt    96:
                     97:        /* Get buffer to use from user */
1.21      deraadt    98:        if ((curbp->b_altb == NULL) &&
                     99:            ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
1.34      vincent   100:                bufp = eread("Switch to buffer in other window: ", bufn, NBUFN,
1.55      deraadt   101:                    EFNEW | EFBUF);
1.1       deraadt   102:        else
1.34      vincent   103:                bufp = eread("Switch to buffer in other window: (default %s) ",
1.55      deraadt   104:                    bufn, NBUFN, EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname);
1.34      vincent   105:        if (bufp == NULL)
1.37      db        106:                return (ABORT);
1.44      kjell     107:        if (bufp[0] == '\0' && curbp->b_altb != NULL)
1.3       millert   108:                bp = curbp->b_altb;
                    109:        else if ((bp = bfind(bufn, TRUE)) == NULL)
1.37      db        110:                return (FALSE);
1.59      kjell     111:        if (bp == curbp)
                    112:                return (splitwind(f, n));
1.71      kjell     113:        /* and put it in a new, non-ephemeral window */
                    114:        if ((wp = popbuf(bp, WNONE)) == NULL)
1.37      db        115:                return (FALSE);
1.1       deraadt   116:        curbp = bp;
                    117:        curwp = wp;
1.37      db        118:        return (TRUE);
1.1       deraadt   119: }
                    120:
                    121: /*
                    122:  * Dispose of a buffer, by name.
                    123:  * Ask for the name. Look it up (don't get too
                    124:  * upset if it isn't there at all!). Clear the buffer (ask
                    125:  * if the buffer has been changed). Then free the header
1.69      kjell     126:  * line and the buffer header. Bound to "C-X k".
1.1       deraadt   127:  */
1.3       millert   128: /* ARGSUSED */
                    129: int
1.35      jfb       130: killbuffer_cmd(int f, int n)
1.1       deraadt   131: {
1.52      deraadt   132:        struct buffer *bp;
1.34      vincent   133:        char    bufn[NBUFN], *bufp;
1.3       millert   134:
1.40      kjell     135:        if ((bufp = eread("Kill buffer: (default %s) ", bufn, NBUFN,
                    136:            EFNUL | EFNEW | EFBUF, curbp->b_bname)) == NULL)
1.37      db        137:                return (ABORT);
1.44      kjell     138:        else if (bufp[0] == '\0')
1.3       millert   139:                bp = curbp;
                    140:        else if ((bp = bfind(bufn, FALSE)) == NULL)
1.37      db        141:                return (FALSE);
                    142:        return (killbuffer(bp));
1.35      jfb       143: }
                    144:
                    145: int
1.52      deraadt   146: killbuffer(struct buffer *bp)
1.35      jfb       147: {
1.52      deraadt   148:        struct buffer *bp1;
                    149:        struct buffer *bp2;
                    150:        struct mgwin  *wp;
1.41      kjell     151:        int s;
1.48      deraadt   152:        struct undo_rec *rec, *next;
1.3       millert   153:
                    154:        /*
1.37      db        155:         * Find some other buffer to display. Try the alternate buffer,
1.3       millert   156:         * then the first different buffer in the buffer list.  If there's
                    157:         * only one buffer, create buffer *scratch* and make it the alternate
                    158:         * buffer.  Return if *scratch* is only buffer...
1.1       deraadt   159:         */
                    160:        if ((bp1 = bp->b_altb) == NULL) {
                    161:                bp1 = (bp == bheadp) ? bp->b_bufp : bheadp;
                    162:                if (bp1 == NULL) {
                    163:                        /* only one buffer. see if it's *scratch* */
1.3       millert   164:                        if (bp == bfind("*scratch*", FALSE))
1.49      kjell     165:                                return (TRUE);
1.1       deraadt   166:                        /* create *scratch* for alternate buffer */
1.3       millert   167:                        if ((bp1 = bfind("*scratch*", TRUE)) == NULL)
1.37      db        168:                                return (FALSE);
1.1       deraadt   169:                }
                    170:        }
1.41      kjell     171:        if ((s = bclear(bp)) != TRUE)
                    172:                return (s);
1.1       deraadt   173:        for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp) {
1.3       millert   174:                if (wp->w_bufp == bp) {
                    175:                        bp2 = bp1->b_altb;      /* save alternate buffer */
1.58      kjell     176:                        if (showbuffer(bp1, wp, WFMODE | WFFRAME | WFFULL))
1.3       millert   177:                                bp1->b_altb = bp2;
                    178:                        else
                    179:                                bp1 = bp2;
                    180:                }
                    181:        }
                    182:        if (bp == curbp)
                    183:                curbp = bp1;
1.62      kjell     184:        free(bp->b_headp);                      /* Release header line.  */
1.3       millert   185:        bp2 = NULL;                             /* Find the header.      */
1.1       deraadt   186:        bp1 = bheadp;
                    187:        while (bp1 != bp) {
                    188:                if (bp1->b_altb == bp)
                    189:                        bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb;
                    190:                bp2 = bp1;
                    191:                bp1 = bp1->b_bufp;
                    192:        }
1.3       millert   193:        bp1 = bp1->b_bufp;                      /* Next one in chain.    */
                    194:        if (bp2 == NULL)                        /* Unlink it.            */
1.1       deraadt   195:                bheadp = bp1;
                    196:        else
                    197:                bp2->b_bufp = bp1;
1.3       millert   198:        while (bp1 != NULL) {                   /* Finish with altb's    */
1.1       deraadt   199:                if (bp1->b_altb == bp)
                    200:                        bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb;
                    201:                bp1 = bp1->b_bufp;
                    202:        }
1.74      oga       203:        rec = TAILQ_FIRST(&bp->b_undo);
                    204:
1.46      kjell     205:        while (rec != NULL) {
1.74      oga       206:                next = TAILQ_NEXT(rec, next);
1.46      kjell     207:                free_undo_record(rec);
                    208:                rec = next;
                    209:        }
                    210:
1.54      kjell     211:        free(bp->b_bname);                      /* Release name block    */
1.3       millert   212:        free(bp);                               /* Release buffer block */
1.37      db        213:        return (TRUE);
1.1       deraadt   214: }
                    215:
                    216: /*
                    217:  * Save some buffers - just call anycb with the arg flag.
                    218:  */
1.3       millert   219: /* ARGSUSED */
                    220: int
1.26      vincent   221: savebuffers(int f, int n)
1.1       deraadt   222: {
1.3       millert   223:        if (anycb(f) == ABORT)
1.37      db        224:                return (ABORT);
                    225:        return (TRUE);
1.1       deraadt   226: }
                    227:
                    228: /*
1.19      art       229:  * Listing buffers.
                    230:  */
                    231: static int listbuf_ncol;
                    232:
                    233: static int     listbuf_goto_buffer(int f, int n);
1.39      jason     234: static int     listbuf_goto_buffer_one(int f, int n);
                    235: static int     listbuf_goto_buffer_helper(int f, int n, int only);
1.19      art       236:
                    237: static PF listbuf_pf[] = {
1.37      db        238:        listbuf_goto_buffer
1.19      art       239: };
1.39      jason     240: static PF listbuf_one[] = {
                    241:        listbuf_goto_buffer_one
                    242: };
                    243:
1.19      art       244:
1.39      jason     245: static struct KEYMAPE (2 + IMAPEXT) listbufmap = {
                    246:        2,
                    247:        2 + IMAPEXT,
1.19      art       248:        rescan,
                    249:        {
1.39      jason     250:                {
1.45      deraadt   251:                        CCHR('M'), CCHR('M'), listbuf_pf, NULL
1.39      jason     252:                },
                    253:                {
1.45      deraadt   254:                        '1', '1', listbuf_one, NULL
1.39      jason     255:                }
1.19      art       256:        }
                    257: };
                    258:
                    259: /*
1.1       deraadt   260:  * Display the buffer list. This is done
                    261:  * in two parts. The "makelist" routine figures out
                    262:  * the text, and puts it in a buffer. "popbuf"
                    263:  * then pops the data onto the screen. Bound to
                    264:  * "C-X C-B".
                    265:  */
1.3       millert   266: /* ARGSUSED */
                    267: int
1.26      vincent   268: listbuffers(int f, int n)
1.1       deraadt   269: {
1.52      deraadt   270:        static int               initialized = 0;
                    271:        struct buffer           *bp;
                    272:        struct mgwin            *wp;
1.1       deraadt   273:
1.19      art       274:        if (!initialized) {
                    275:                maps_add((KEYMAP *)&listbufmap, "listbufmap");
                    276:                initialized = 1;
                    277:        }
                    278:
1.71      kjell     279:        if ((bp = makelist()) == NULL || (wp = popbuf(bp, WNONE)) == NULL)
1.37      db        280:                return (FALSE);
                    281:        wp->w_dotp = bp->b_dotp; /* fix up if window already on screen */
1.1       deraadt   282:        wp->w_doto = bp->b_doto;
1.19      art       283:        bp->b_modes[0] = name_mode("fundamental");
                    284:        bp->b_modes[1] = name_mode("listbufmap");
                    285:        bp->b_nmodes = 1;
                    286:
1.37      db        287:        return (TRUE);
1.1       deraadt   288: }
                    289:
                    290: /*
                    291:  * This routine rebuilds the text for the
1.37      db        292:  * list buffers command. Return pointer
                    293:  * to new list if everything works.
                    294:  * Return NULL if there is an error (if
                    295:  * there is no memory).
1.1       deraadt   296:  */
1.52      deraadt   297: static struct buffer *
1.26      vincent   298: makelist(void)
1.3       millert   299: {
1.52      deraadt   300:        int             w = ncol / 2;
                    301:        struct buffer   *bp, *blp;
                    302:        struct line     *lp;
1.19      art       303:
1.3       millert   304:        if ((blp = bfind("*Buffer List*", TRUE)) == NULL)
1.37      db        305:                return (NULL);
1.3       millert   306:        if (bclear(blp) != TRUE)
1.37      db        307:                return (NULL);
1.3       millert   308:        blp->b_flag &= ~BFCHG;          /* Blow away old.        */
1.28      vincent   309:        blp->b_flag |= BFREADONLY;
1.1       deraadt   310:
1.19      art       311:        listbuf_ncol = ncol;            /* cache ncol for listbuf_goto_buffer */
                    312:
1.11      art       313:        if (addlinef(blp, "%-*s%s", w, " MR Buffer", "Size   File") == FALSE ||
                    314:            addlinef(blp, "%-*s%s", w, " -- ------", "----   ----") == FALSE)
1.37      db        315:                return (NULL);
1.11      art       316:
                    317:        for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
                    318:                RSIZE nbytes;
                    319:
1.3       millert   320:                nbytes = 0;                     /* Count bytes in buf.   */
1.1       deraadt   321:                if (bp != blp) {
1.63      kjell     322:                        lp = bfirstlp(bp);
1.62      kjell     323:                        while (lp != bp->b_headp) {
1.3       millert   324:                                nbytes += llength(lp) + 1;
1.1       deraadt   325:                                lp = lforw(lp);
                    326:                        }
1.3       millert   327:                        if (nbytes)
                    328:                                nbytes--;       /* no bonus newline      */
1.1       deraadt   329:                }
1.11      art       330:
1.19      art       331:                if (addlinef(blp, "%c%c%c %-*.*s%c%-6d %-*s",
1.11      art       332:                    (bp == curbp) ? '.' : ' ',  /* current buffer ? */
                    333:                    ((bp->b_flag & BFCHG) != 0) ? '*' : ' ',    /* changed ? */
1.27      vincent   334:                    ((bp->b_flag & BFREADONLY) != 0) ? ' ' : '*',
1.19      art       335:                    w - 5,              /* four chars already written */
                    336:                    w - 5,              /* four chars already written */
1.11      art       337:                    bp->b_bname,        /* buffer name */
1.19      art       338:                    strlen(bp->b_bname) < w - 5 ? ' ' : '$', /* truncated? */
1.11      art       339:                    nbytes,             /* buffer size */
                    340:                    w - 7,              /* seven chars already written */
                    341:                    bp->b_fname) == FALSE)
1.37      db        342:                        return (NULL);
1.1       deraadt   343:        }
1.63      kjell     344:        blp->b_dotp = bfirstlp(blp);            /* put dot at beginning of
1.3       millert   345:                                                 * buffer */
1.1       deraadt   346:        blp->b_doto = 0;
1.37      db        347:        return (blp);                           /* All done              */
1.19      art       348: }
                    349:
                    350: static int
                    351: listbuf_goto_buffer(int f, int n)
                    352: {
1.39      jason     353:        return (listbuf_goto_buffer_helper(f, n, 0));
                    354: }
                    355:
                    356: static int
                    357: listbuf_goto_buffer_one(int f, int n)
                    358: {
                    359:        return (listbuf_goto_buffer_helper(f, n, 1));
                    360: }
                    361:
                    362: static int
                    363: listbuf_goto_buffer_helper(int f, int n, int only)
                    364: {
1.52      deraadt   365:        struct buffer   *bp;
                    366:        struct mgwin    *wp;
                    367:        char            *line = NULL;
                    368:        int              i, ret = FALSE;
1.19      art       369:
                    370:        if (curwp->w_dotp->l_text[listbuf_ncol/2 - 1] == '$') {
                    371:                ewprintf("buffer name truncated");
1.37      db        372:                return (FALSE);
1.19      art       373:        }
                    374:
                    375:        if ((line = malloc(listbuf_ncol/2)) == NULL)
1.37      db        376:                return (FALSE);
1.19      art       377:
                    378:        memcpy(line, curwp->w_dotp->l_text + 4, listbuf_ncol/2 - 5);
                    379:        for (i = listbuf_ncol/2 - 6; i > 0; i--) {
                    380:                if (line[i] != ' ') {
                    381:                        line[i + 1] = '\0';
                    382:                        break;
                    383:                }
                    384:        }
1.37      db        385:        if (i == 0)
1.42      cloder    386:                goto cleanup;
1.19      art       387:
                    388:        for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
                    389:                if (strcmp(bp->b_bname, line) == 0)
                    390:                        break;
                    391:        }
1.37      db        392:        if (bp == NULL)
1.42      cloder    393:                goto cleanup;
1.37      db        394:
1.71      kjell     395:        if ((wp = popbuf(bp, WNONE)) == NULL)
1.42      cloder    396:                goto cleanup;
1.19      art       397:        curbp = bp;
                    398:        curwp = wp;
1.39      jason     399:
                    400:        if (only)
1.42      cloder    401:                ret = (onlywind(f, n));
                    402:        else
                    403:                ret = TRUE;
                    404:
                    405: cleanup:
                    406:        free(line);
1.19      art       407:
1.42      cloder    408:        return (ret);
1.1       deraadt   409: }
                    410:
                    411: /*
1.47      kjell     412:  * The argument "fmt" points to a format string.  Append this line to the
1.3       millert   413:  * buffer. Handcraft the EOL on the end.  Return TRUE if it worked and
1.1       deraadt   414:  * FALSE if you ran out of room.
                    415:  */
1.3       millert   416: int
1.52      deraadt   417: addlinef(struct buffer *bp, char *fmt, ...)
1.3       millert   418: {
1.52      deraadt   419:        va_list          ap;
                    420:        struct line     *lp;
1.1       deraadt   421:
1.30      vincent   422:        if ((lp = lalloc(0)) == NULL)
                    423:                return (FALSE);
1.8       art       424:        va_start(ap, fmt);
1.30      vincent   425:        if (vasprintf(&lp->l_text, fmt, ap) == -1) {
                    426:                lfree(lp);
1.16      deraadt   427:                va_end(ap);
1.30      vincent   428:                return (FALSE);
1.16      deraadt   429:        }
1.30      vincent   430:        lp->l_used = strlen(lp->l_text);
1.8       art       431:        va_end(ap);
                    432:
1.62      kjell     433:        bp->b_headp->l_bp->l_fp = lp;           /* Hook onto the end     */
                    434:        lp->l_bp = bp->b_headp->l_bp;
                    435:        bp->b_headp->l_bp = lp;
                    436:        lp->l_fp = bp->b_headp;
1.60      kjell     437:        bp->b_lines++;
1.8       art       438:
1.37      db        439:        return (TRUE);
1.1       deraadt   440: }
                    441:
                    442: /*
1.3       millert   443:  * Look through the list of buffers, giving the user a chance to save them.
1.51      kjell     444:  * Return TRUE if there are any changed buffers afterwards.  Buffers that don't
                    445:  * have an associated file don't count.  Return FALSE if there are no changed
                    446:  * buffers.  Return ABORT if an error occurs or if the user presses c-g.
1.3       millert   447:  */
                    448: int
1.26      vincent   449: anycb(int f)
1.3       millert   450: {
1.52      deraadt   451:        struct buffer   *bp;
1.79      lum       452:        int              s = FALSE, save = FALSE, save2 = FALSE, ret;
1.53      kjell     453:        char             pbuf[NFILEN + 11];
1.1       deraadt   454:
                    455:        for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
1.21      deraadt   456:                if (bp->b_fname != NULL && *(bp->b_fname) != '\0' &&
                    457:                    (bp->b_flag & BFCHG) != 0) {
1.53      kjell     458:                        ret = snprintf(pbuf, sizeof(pbuf), "Save file %s",
1.17      deraadt   459:                            bp->b_fname);
1.53      kjell     460:                        if (ret < 0 || ret >= sizeof(pbuf)) {
1.51      kjell     461:                                ewprintf("Error: filename too long!");
1.81      lum       462:                                return (UERROR);
1.51      kjell     463:                        }
1.53      kjell     464:                        if ((f == TRUE || (save = eyorn(pbuf)) == TRUE) &&
1.79      lum       465:                            (save2 = buffsave(bp)) == TRUE) {
1.1       deraadt   466:                                bp->b_flag &= ~BFCHG;
                    467:                                upmodes(bp);
1.79      lum       468:                        } else {
                    469:                                if (save2 == FIOERR)
                    470:                                        return (save2);
1.3       millert   471:                                s = TRUE;
1.79      lum       472:                        }
1.3       millert   473:                        if (save == ABORT)
                    474:                                return (save);
1.1       deraadt   475:                        save = TRUE;
                    476:                }
                    477:        }
                    478:        if (save == FALSE /* && kbdmop == NULL */ )     /* experimental */
                    479:                ewprintf("(No files need saving)");
1.37      db        480:        return (s);
1.1       deraadt   481: }
                    482:
                    483: /*
                    484:  * Search for a buffer, by name.
                    485:  * If not found, and the "cflag" is TRUE,
1.57      kjell     486:  * create a new buffer. Return pointer to the found
                    487:  * (or new) buffer.
1.1       deraadt   488:  */
1.52      deraadt   489: struct buffer *
1.26      vincent   490: bfind(const char *bname, int cflag)
1.3       millert   491: {
1.52      deraadt   492:        struct buffer   *bp;
1.1       deraadt   493:
                    494:        bp = bheadp;
                    495:        while (bp != NULL) {
1.7       art       496:                if (strcmp(bname, bp->b_bname) == 0)
1.37      db        497:                        return (bp);
1.1       deraadt   498:                bp = bp->b_bufp;
                    499:        }
1.3       millert   500:        if (cflag != TRUE)
1.37      db        501:                return (NULL);
1.29      vincent   502:
1.65      kjell     503:        bp = bnew(bname);
1.57      kjell     504:
                    505:        return (bp);
                    506: }
                    507:
                    508: /*
                    509:  * Create a new buffer and put it in the list of
1.66      deraadt   510:  * all buffers.
1.57      kjell     511:  */
                    512: static struct buffer *
1.65      kjell     513: bnew(const char *bname)
1.57      kjell     514: {
1.66      deraadt   515:        struct buffer   *bp;
1.57      kjell     516:        struct line     *lp;
                    517:        int              i;
1.72      kjell     518:        size_t          len;
1.57      kjell     519:
1.52      deraadt   520:        bp = calloc(1, sizeof(struct buffer));
1.32      vincent   521:        if (bp == NULL) {
1.52      deraadt   522:                ewprintf("Can't get %d bytes", sizeof(struct buffer));
1.37      db        523:                return (NULL);
1.1       deraadt   524:        }
                    525:        if ((lp = lalloc(0)) == NULL) {
1.29      vincent   526:                free(bp);
1.37      db        527:                return (NULL);
1.1       deraadt   528:        }
1.3       millert   529:        bp->b_altb = bp->b_bufp = NULL;
                    530:        bp->b_dotp = lp;
                    531:        bp->b_doto = 0;
1.1       deraadt   532:        bp->b_markp = NULL;
                    533:        bp->b_marko = 0;
1.3       millert   534:        bp->b_flag = defb_flag;
1.72      kjell     535:        /* if buffer name starts and ends with '*', we ignore changes */
                    536:        len = strlen(bname);
                    537:        if (len) {
                    538:                if (bname[0] == '*' && bname[len - 1] == '*')
                    539:                        bp->b_flag |= BFIGNDIRTY;
                    540:        }
1.3       millert   541:        bp->b_nwnd = 0;
1.62      kjell     542:        bp->b_headp = lp;
1.1       deraadt   543:        bp->b_nmodes = defb_nmodes;
1.74      oga       544:        TAILQ_INIT(&bp->b_undo);
1.46      kjell     545:        bp->b_undoptr = NULL;
1.1       deraadt   546:        i = 0;
                    547:        do {
1.3       millert   548:                bp->b_modes[i] = defb_modes[i];
                    549:        } while (i++ < defb_nmodes);
1.1       deraadt   550:        bp->b_fname[0] = '\0';
1.57      kjell     551:        bp->b_cwd[0] = '\0';
1.1       deraadt   552:        bzero(&bp->b_fi, sizeof(bp->b_fi));
                    553:        lp->l_fp = lp;
                    554:        lp->l_bp = lp;
                    555:        bp->b_bufp = bheadp;
                    556:        bheadp = bp;
1.60      kjell     557:        bp->b_dotline = bp->b_markline = 1;
1.61      kjell     558:        bp->b_lines = 1;
1.65      kjell     559:        if ((bp->b_bname = strdup(bname)) == NULL) {
                    560:                ewprintf("Can't get %d bytes", strlen(bname) + 1);
                    561:                return (NULL);
                    562:        }
1.57      kjell     563:
1.37      db        564:        return (bp);
1.1       deraadt   565: }
                    566:
                    567: /*
                    568:  * This routine blows away all of the text
                    569:  * in a buffer. If the buffer is marked as changed
                    570:  * then we ask if it is ok to blow it away; this is
                    571:  * to save the user the grief of losing text. The
                    572:  * window chain is nearly always wrong if this gets
                    573:  * called; the caller must arrange for the updates
                    574:  * that are required. Return TRUE if everything
                    575:  * looks good.
                    576:  */
1.3       millert   577: int
1.52      deraadt   578: bclear(struct buffer *bp)
1.3       millert   579: {
1.52      deraadt   580:        struct line     *lp;
                    581:        int              s;
1.1       deraadt   582:
1.72      kjell     583:        /* Has buffer changed, and do we care? */
                    584:        if (!(bp->b_flag & BFIGNDIRTY) && (bp->b_flag & BFCHG) != 0 &&
1.21      deraadt   585:            (s = eyesno("Buffer modified; kill anyway")) != TRUE)
1.1       deraadt   586:                return (s);
1.3       millert   587:        bp->b_flag &= ~BFCHG;   /* Not changed           */
1.62      kjell     588:        while ((lp = lforw(bp->b_headp)) != bp->b_headp)
1.1       deraadt   589:                lfree(lp);
1.62      kjell     590:        bp->b_dotp = bp->b_headp;       /* Fix dot */
1.3       millert   591:        bp->b_doto = 0;
                    592:        bp->b_markp = NULL;     /* Invalidate "mark"     */
1.1       deraadt   593:        bp->b_marko = 0;
1.60      kjell     594:        bp->b_dotline = bp->b_markline = 1;
1.61      kjell     595:        bp->b_lines = 1;
1.60      kjell     596:
1.37      db        597:        return (TRUE);
1.1       deraadt   598: }
                    599:
                    600: /*
                    601:  * Display the given buffer in the given window. Flags indicated
1.68      kjell     602:  * action on redisplay. Update modified flag so insert loop can check it.
1.1       deraadt   603:  */
1.3       millert   604: int
1.52      deraadt   605: showbuffer(struct buffer *bp, struct mgwin *wp, int flags)
1.3       millert   606: {
1.52      deraadt   607:        struct buffer   *obp;
                    608:        struct mgwin    *owp;
1.1       deraadt   609:
1.68      kjell     610:        /* Ensure file has not been modified elsewhere */
                    611:        if (fchecktime(bp) != TRUE)
                    612:                bp->b_flag |= BFDIRTY;
                    613:
1.32      vincent   614:        if (wp->w_bufp == bp) { /* Easy case! */
1.70      kjell     615:                wp->w_rflag |= flags;
1.37      db        616:                return (TRUE);
1.1       deraadt   617:        }
1.37      db        618:        /* First, detach the old buffer from the window */
1.1       deraadt   619:        if ((bp->b_altb = obp = wp->w_bufp) != NULL) {
                    620:                if (--obp->b_nwnd == 0) {
1.3       millert   621:                        obp->b_dotp = wp->w_dotp;
                    622:                        obp->b_doto = wp->w_doto;
1.1       deraadt   623:                        obp->b_markp = wp->w_markp;
                    624:                        obp->b_marko = wp->w_marko;
1.60      kjell     625:                        obp->b_dotline = wp->w_dotline;
                    626:                        obp->b_markline = wp->w_markline;
1.1       deraadt   627:                }
                    628:        }
                    629:        /* Now, attach the new buffer to the window */
                    630:        wp->w_bufp = bp;
                    631:
1.3       millert   632:        if (bp->b_nwnd++ == 0) {        /* First use.            */
                    633:                wp->w_dotp = bp->b_dotp;
                    634:                wp->w_doto = bp->b_doto;
1.1       deraadt   635:                wp->w_markp = bp->b_markp;
                    636:                wp->w_marko = bp->b_marko;
1.60      kjell     637:                wp->w_dotline = bp->b_dotline;
                    638:                wp->w_markline = bp->b_markline;
1.1       deraadt   639:        } else
1.3       millert   640:                /* already on screen, steal values from other window */
1.1       deraadt   641:                for (owp = wheadp; owp != NULL; owp = wp->w_wndp)
                    642:                        if (wp->w_bufp == bp && owp != wp) {
1.3       millert   643:                                wp->w_dotp = owp->w_dotp;
                    644:                                wp->w_doto = owp->w_doto;
1.1       deraadt   645:                                wp->w_markp = owp->w_markp;
                    646:                                wp->w_marko = owp->w_marko;
1.60      kjell     647:                                wp->w_dotline = owp->w_dotline;
1.64      kjell     648:                                wp->w_markline = owp->w_markline;
1.1       deraadt   649:                                break;
                    650:                        }
1.70      kjell     651:        wp->w_rflag |= WFMODE | flags;
1.56      kjell     652:        return (TRUE);
                    653: }
                    654:
                    655: /*
                    656:  * Augment a buffer name with a number, if necessary
                    657:  *
                    658:  * If more than one file of the same basename() is open,
                    659:  * the additional buffers are named "file<2>", "file<3>", and
                    660:  * so forth.  This function adjusts a buffer name to
                    661:  * include the number, if necessary.
                    662:  */
                    663: int
1.57      kjell     664: augbname(char *bn, const char *fn, size_t bs)
1.56      kjell     665: {
1.66      deraadt   666:        int      count;
1.56      kjell     667:        size_t   remain, len;
                    668:
1.77      kjell     669:        if ((len = xbasename(bn, fn, bs)) >= bs)
1.56      kjell     670:                return (FALSE);
                    671:
                    672:        remain = bs - len;
                    673:        for (count = 2; bfind(bn, FALSE) != NULL; count++)
                    674:                snprintf(bn + len, remain, "<%d>", count);
                    675:
1.37      db        676:        return (TRUE);
1.1       deraadt   677: }
                    678:
                    679: /*
                    680:  * Pop the buffer we got passed onto the screen.
                    681:  * Returns a status.
                    682:  */
1.52      deraadt   683: struct mgwin *
1.71      kjell     684: popbuf(struct buffer *bp, int flags)
1.3       millert   685: {
1.52      deraadt   686:        struct mgwin    *wp;
1.1       deraadt   687:
1.3       millert   688:        if (bp->b_nwnd == 0) {  /* Not on screen yet.    */
1.71      kjell     689:                /*
                    690:                 * Pick a window for a pop-up.
                    691:                 * If only one window, split the screen.
                    692:                 * Flag the new window as ephemeral
                    693:                 */
                    694:                if (wheadp->w_wndp == NULL &&
                    695:                    splitwind(FFOTHARG, flags) == FALSE)
                    696:                        return (NULL);
                    697:
                    698:                /*
                    699:                 * Pick the uppermost window that isn't
                    700:                 * the current window. An LRU algorithm
                    701:                 * might be better. Return a pointer, or NULL on error.
                    702:                 */
                    703:                wp = wheadp;
                    704:
                    705:                while (wp != NULL && wp == curwp)
                    706:                        wp = wp->w_wndp;
1.1       deraadt   707:        } else
                    708:                for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
                    709:                        if (wp->w_bufp == bp) {
1.70      kjell     710:                                wp->w_rflag |= WFFULL | WFFRAME;
1.37      db        711:                                return (wp);
1.1       deraadt   712:                        }
1.58      kjell     713:        if (showbuffer(bp, wp, WFFULL) != TRUE)
1.37      db        714:                return (NULL);
                    715:        return (wp);
1.1       deraadt   716: }
                    717:
                    718: /*
                    719:  * Insert another buffer at dot.  Very useful.
                    720:  */
1.3       millert   721: /* ARGSUSED */
                    722: int
1.26      vincent   723: bufferinsert(int f, int n)
1.1       deraadt   724: {
1.52      deraadt   725:        struct buffer *bp;
                    726:        struct line   *clp;
1.36      deraadt   727:        int     clo, nline;
                    728:        char    bufn[NBUFN], *bufp;
1.1       deraadt   729:
                    730:        /* Get buffer to use from user */
                    731:        if (curbp->b_altb != NULL)
1.34      vincent   732:                bufp = eread("Insert buffer: (default %s) ", bufn, NBUFN,
1.40      kjell     733:                    EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname);
1.1       deraadt   734:        else
1.38      cloder    735:                bufp = eread("Insert buffer: ", bufn, NBUFN, EFNEW | EFBUF);
1.34      vincent   736:        if (bufp == NULL)
1.37      db        737:                return (ABORT);
1.34      vincent   738:        if (bufp[0] == '\0' && curbp->b_altb != NULL)
1.3       millert   739:                bp = curbp->b_altb;
                    740:        else if ((bp = bfind(bufn, FALSE)) == NULL)
1.37      db        741:                return (FALSE);
1.1       deraadt   742:
1.3       millert   743:        if (bp == curbp) {
1.1       deraadt   744:                ewprintf("Cannot insert buffer into self");
1.37      db        745:                return (FALSE);
1.1       deraadt   746:        }
                    747:        /* insert the buffer */
                    748:        nline = 0;
1.63      kjell     749:        clp = bfirstlp(bp);
1.3       millert   750:        for (;;) {
1.1       deraadt   751:                for (clo = 0; clo < llength(clp); clo++)
                    752:                        if (linsert(1, lgetc(clp, clo)) == FALSE)
1.37      db        753:                                return (FALSE);
1.62      kjell     754:                if ((clp = lforw(clp)) == bp->b_headp)
1.3       millert   755:                        break;
                    756:                if (newline(FFRAND, 1) == FALSE)        /* fake newline */
1.37      db        757:                        return (FALSE);
1.1       deraadt   758:                nline++;
                    759:        }
1.3       millert   760:        if (nline == 1)
                    761:                ewprintf("[Inserted 1 line]");
                    762:        else
                    763:                ewprintf("[Inserted %d lines]", nline);
1.1       deraadt   764:
1.37      db        765:        clp = curwp->w_linep;           /* cosmetic adjustment  */
1.3       millert   766:        if (curwp->w_dotp == clp) {     /* for offscreen insert */
1.62      kjell     767:                while (nline-- && lback(clp) != curbp->b_headp)
1.1       deraadt   768:                        clp = lback(clp);
1.37      db        769:                curwp->w_linep = clp;   /* adjust framing.      */
1.70      kjell     770:                curwp->w_rflag |= WFFULL;
1.1       deraadt   771:        }
                    772:        return (TRUE);
                    773: }
                    774:
                    775: /*
                    776:  * Turn off the dirty bit on this buffer.
                    777:  */
1.3       millert   778: /* ARGSUSED */
                    779: int
1.26      vincent   780: notmodified(int f, int n)
1.1       deraadt   781: {
1.52      deraadt   782:        struct mgwin *wp;
1.1       deraadt   783:
                    784:        curbp->b_flag &= ~BFCHG;
1.3       millert   785:        wp = wheadp;            /* Update mode lines.    */
1.1       deraadt   786:        while (wp != NULL) {
                    787:                if (wp->w_bufp == curbp)
1.70      kjell     788:                        wp->w_rflag |= WFMODE;
1.1       deraadt   789:                wp = wp->w_wndp;
                    790:        }
                    791:        ewprintf("Modification-flag cleared");
1.37      db        792:        return (TRUE);
1.1       deraadt   793: }
                    794:
                    795: /*
1.78      lum       796:  * Popbuf and set all windows to top of buffer.
1.1       deraadt   797:  */
1.3       millert   798: int
1.71      kjell     799: popbuftop(struct buffer *bp, int flags)
1.1       deraadt   800: {
1.52      deraadt   801:        struct mgwin *wp;
1.1       deraadt   802:
1.63      kjell     803:        bp->b_dotp = bfirstlp(bp);
1.3       millert   804:        bp->b_doto = 0;
                    805:        if (bp->b_nwnd != 0) {
                    806:                for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
                    807:                        if (wp->w_bufp == bp) {
                    808:                                wp->w_dotp = bp->b_dotp;
                    809:                                wp->w_doto = 0;
1.70      kjell     810:                                wp->w_rflag |= WFFULL;
1.3       millert   811:                        }
                    812:        }
1.71      kjell     813:        return (popbuf(bp, flags) != NULL);
1.1       deraadt   814: }
1.57      kjell     815:
                    816: /*
                    817:  * Return the working directory for the current buffer, terminated
                    818:  * with a '/'. First, try to extract it from the current buffer's
                    819:  * filename. If that fails, use global cwd.
                    820:  */
                    821: int
                    822: getbufcwd(char *path, size_t plen)
                    823: {
                    824:        char cwd[NFILEN];
                    825:
                    826:        if (plen == 0)
                    827:                return (FALSE);
                    828:
1.67      kjell     829:        if (globalwd == FALSE && curbp->b_cwd[0] != '\0') {
1.57      kjell     830:                (void)strlcpy(path, curbp->b_cwd, plen);
                    831:        } else {
                    832:                if (getcwdir(cwd, sizeof(cwd)) == FALSE)
                    833:                        goto error;
                    834:                (void)strlcpy(path, cwd, plen);
                    835:        }
                    836:        return (TRUE);
                    837: error:
                    838:        path[0] = '\0';
                    839:        return (FALSE);
                    840: }
                    841:
1.68      kjell     842: /*
1.69      kjell     843:  * Ensures a buffer has not been modified elsewhere; e.g. on disk.
                    844:  * Prompt the user if it has.
                    845:  * Returns TRUE if it has NOT (i.e. buffer is ok to edit).
                    846:  * FALSE or ABORT otherwise
1.68      kjell     847:  */
                    848: int
                    849: checkdirty(struct buffer *bp)
                    850: {
                    851:        int s;
1.83      florian   852:
                    853:        if ((bp->b_flag & (BFCHG | BFDIRTY)) == 0)
                    854:                if (fchecktime(bp) != TRUE)
                    855:                        bp->b_flag |= BFDIRTY;
                    856:
1.68      kjell     857:        if ((bp->b_flag & (BFDIRTY | BFIGNDIRTY)) == BFDIRTY) {
1.84      florian   858:                s = eynorr("File changed on disk; really edit the buffer");
                    859:                switch (s) {
                    860:                case TRUE:
                    861:                        bp->b_flag &= ~BFDIRTY;
                    862:                        bp->b_flag |= BFIGNDIRTY;
                    863:                        return (TRUE);
                    864:                case REVERT:
                    865:                        dorevert();
                    866:                        return (FALSE);
                    867:                default:
1.68      kjell     868:                        return (s);
1.84      florian   869:                }
1.68      kjell     870:        }
                    871:
                    872:        return (TRUE);
                    873: }
1.82      jasper    874:
                    875: /*
                    876:  * Revert the current buffer to whatever is on disk.
                    877:  */
                    878: /* ARGSUSED */
                    879: int
                    880: revertbuffer(int f, int n)
                    881: {
                    882:        char fbuf[NFILEN + 32];
                    883:
1.85      florian   884:        if (curbp->b_fname[0] == 0) {
1.82      jasper    885:                ewprintf("Cannot revert buffer not associated with any files.");
                    886:                return (FALSE);
                    887:        }
                    888:
1.85      florian   889:        snprintf(fbuf, sizeof(fbuf), "Revert buffer from file %s",
                    890:            curbp->b_fname);
1.82      jasper    891:
1.85      florian   892:        if (eyorn(fbuf) == TRUE)
1.84      florian   893:                return dorevert();
1.82      jasper    894:
1.84      florian   895:        return (FALSE);
                    896: }
1.82      jasper    897:
1.84      florian   898: int
1.86      haesbaer  899: dorevert(void)
1.84      florian   900: {
                    901:        int lineno;
1.82      jasper    902:
1.85      florian   903:        if (access(curbp->b_fname, F_OK|R_OK) != 0) {
1.84      florian   904:                if (errno == ENOENT)
                    905:                        ewprintf("File %s no longer exists!",
1.85      florian   906:                            curbp->b_fname);
1.84      florian   907:                else
                    908:                        ewprintf("File %s is no longer readable!",
1.85      florian   909:                            curbp->b_fname);
1.84      florian   910:                return (FALSE);
1.82      jasper    911:        }
                    912:
1.84      florian   913:        /* Save our current line, so we can go back after reloading. */
1.85      florian   914:        lineno = curwp->w_dotline;
1.84      florian   915:
                    916:        /* Prevent readin from asking if we want to kill the buffer. */
                    917:        curbp->b_flag &= ~BFCHG;
                    918:
1.85      florian   919:        if (readin(curbp->b_fname))
1.84      florian   920:                return(setlineno(lineno));
1.82      jasper    921:        return (FALSE);
                    922: }