[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.68

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