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

Annotation of src/usr.bin/mg/basic.c, Revision 1.40

1.40    ! lum         1: /*     $OpenBSD: basic.c,v 1.39 2013/03/25 11:41:44 florian Exp $      */
1.19      kjell       2:
                      3: /* This file is in the public domain */
1.4       niklas      4:
1.1       deraadt     5: /*
                      6:  *             Basic cursor motion commands.
                      7:  *
                      8:  * The routines in this file are the basic
                      9:  * command functions for moving the cursor around on
                     10:  * the screen, setting mark, and swapping dot with
                     11:  * mark. Only moves between lines, which might make the
                     12:  * current buffer framing bad, are hard.
                     13:  */
1.3       millert    14: #include "def.h"
1.1       deraadt    15:
1.14      vincent    16: #include <ctype.h>
1.1       deraadt    17:
                     18: /*
                     19:  * Go to beginning of line.
                     20:  */
1.3       millert    21: /* ARGSUSED */
                     22: int
1.12      vincent    23: gotobol(int f, int n)
1.1       deraadt    24: {
1.3       millert    25:        curwp->w_doto = 0;
1.1       deraadt    26:        return (TRUE);
                     27: }
                     28:
                     29: /*
                     30:  * Move cursor backwards. Do the
                     31:  * right thing if the count is less than
                     32:  * 0. Error if you try to move back from
                     33:  * the beginning of the buffer.
                     34:  */
1.3       millert    35: /* ARGSUSED */
                     36: int
1.12      vincent    37: backchar(int f, int n)
1.1       deraadt    38: {
1.21      deraadt    39:        struct line   *lp;
1.1       deraadt    40:
1.3       millert    41:        if (n < 0)
1.18      db         42:                return (forwchar(f, -n));
1.1       deraadt    43:        while (n--) {
                     44:                if (curwp->w_doto == 0) {
1.25      kjell      45:                        if ((lp = lback(curwp->w_dotp)) == curbp->b_headp) {
1.40    ! lum        46:                                if (!(f & FFRAND)) {
        !            47:                                        dobeep();
1.1       deraadt    48:                                        ewprintf("Beginning of buffer");
1.40    ! lum        49:                                }
1.1       deraadt    50:                                return (FALSE);
                     51:                        }
1.3       millert    52:                        curwp->w_dotp = lp;
                     53:                        curwp->w_doto = llength(lp);
1.30      kjell      54:                        curwp->w_rflag |= WFMOVE;
1.23      kjell      55:                        curwp->w_dotline--;
1.1       deraadt    56:                } else
                     57:                        curwp->w_doto--;
                     58:        }
1.18      db         59:        return (TRUE);
1.1       deraadt    60: }
                     61:
                     62: /*
                     63:  * Go to end of line.
                     64:  */
1.3       millert    65: /* ARGSUSED */
                     66: int
1.12      vincent    67: gotoeol(int f, int n)
1.1       deraadt    68: {
1.3       millert    69:        curwp->w_doto = llength(curwp->w_dotp);
1.1       deraadt    70:        return (TRUE);
                     71: }
                     72:
                     73: /*
                     74:  * Move cursor forwards. Do the
                     75:  * right thing if the count is less than
                     76:  * 0. Error if you try to move forward
                     77:  * from the end of the buffer.
                     78:  */
1.3       millert    79: /* ARGSUSED */
                     80: int
1.12      vincent    81: forwchar(int f, int n)
1.1       deraadt    82: {
1.3       millert    83:        if (n < 0)
1.18      db         84:                return (backchar(f, -n));
1.1       deraadt    85:        while (n--) {
                     86:                if (curwp->w_doto == llength(curwp->w_dotp)) {
1.3       millert    87:                        curwp->w_dotp = lforw(curwp->w_dotp);
1.25      kjell      88:                        if (curwp->w_dotp == curbp->b_headp) {
1.1       deraadt    89:                                curwp->w_dotp = lback(curwp->w_dotp);
1.40    ! lum        90:                                if (!(f & FFRAND)) {
        !            91:                                        dobeep();
1.1       deraadt    92:                                        ewprintf("End of buffer");
1.40    ! lum        93:                                }
1.18      db         94:                                return (FALSE);
1.1       deraadt    95:                        }
1.3       millert    96:                        curwp->w_doto = 0;
1.23      kjell      97:                        curwp->w_dotline++;
1.30      kjell      98:                        curwp->w_rflag |= WFMOVE;
1.1       deraadt    99:                } else
                    100:                        curwp->w_doto++;
                    101:        }
1.18      db        102:        return (TRUE);
1.1       deraadt   103: }
                    104:
                    105: /*
                    106:  * Go to the beginning of the
1.22      kjell     107:  * buffer. Setting WFFULL is conservative,
1.1       deraadt   108:  * but almost always the case.
                    109:  */
1.3       millert   110: int
1.12      vincent   111: gotobob(int f, int n)
1.1       deraadt   112: {
1.6       art       113:        (void) setmark(f, n);
1.26      kjell     114:        curwp->w_dotp = bfirstlp(curbp);
1.3       millert   115:        curwp->w_doto = 0;
1.30      kjell     116:        curwp->w_rflag |= WFFULL;
1.23      kjell     117:        curwp->w_dotline = 1;
1.18      db        118:        return (TRUE);
1.1       deraadt   119: }
                    120:
                    121: /*
1.37      lum       122:  * Go to the end of the buffer. Leave dot 3 lines from the bottom of the
                    123:  * window if buffer length is longer than window length; same as emacs.
                    124:  * Setting WFFULL is conservative, but almost always the case.
1.1       deraadt   125:  */
1.3       millert   126: int
1.12      vincent   127: gotoeob(int f, int n)
1.1       deraadt   128: {
1.37      lum       129:        struct line     *lp;
                    130:
1.6       art       131:        (void) setmark(f, n);
1.26      kjell     132:        curwp->w_dotp = blastlp(curbp);
1.3       millert   133:        curwp->w_doto = llength(curwp->w_dotp);
1.23      kjell     134:        curwp->w_dotline = curwp->w_bufp->b_lines;
1.37      lum       135:
                    136:        lp = curwp->w_dotp;
                    137:        n = curwp->w_ntrows - 3;
                    138:
                    139:        if (n < curwp->w_bufp->b_lines && n >= 3) {
                    140:                while (n--)
                    141:                        curwp->w_dotp = lback(curwp->w_dotp);
                    142:
                    143:                curwp->w_linep = curwp->w_dotp;
                    144:                curwp->w_dotp = lp;
                    145:        }
1.30      kjell     146:        curwp->w_rflag |= WFFULL;
1.18      db        147:        return (TRUE);
1.1       deraadt   148: }
                    149:
                    150: /*
                    151:  * Move forward by full lines.
                    152:  * If the number of lines to move is less
                    153:  * than zero, call the backward line function to
                    154:  * actually do it. The last command controls how
                    155:  * the goal column is set.
                    156:  */
1.3       millert   157: /* ARGSUSED */
                    158: int
1.12      vincent   159: forwline(int f, int n)
1.1       deraadt   160: {
1.21      deraadt   161:        struct line  *dlp;
1.1       deraadt   162:
                    163:        if (n < 0)
1.18      db        164:                return (backline(f | FFRAND, -n));
1.25      kjell     165:        if ((dlp = curwp->w_dotp) == curbp->b_headp)
1.23      kjell     166:                return(TRUE);
1.14      vincent   167:        if ((lastflag & CFCPCN) == 0)   /* Fix goal. */
1.1       deraadt   168:                setgoal();
                    169:        thisflag |= CFCPCN;
1.3       millert   170:        if (n == 0)
1.18      db        171:                return (TRUE);
1.23      kjell     172:        while (n--) {
1.1       deraadt   173:                dlp = lforw(dlp);
1.25      kjell     174:                if (dlp == curbp->b_headp) {
1.23      kjell     175:                        curwp->w_dotp = lback(dlp);
                    176:                        curwp->w_doto = llength(curwp->w_dotp);
1.30      kjell     177:                        curwp->w_rflag |= WFMOVE;
1.23      kjell     178:                        return (TRUE);
1.1       deraadt   179:                }
1.23      kjell     180:                curwp->w_dotline++;
1.1       deraadt   181:        }
1.30      kjell     182:        curwp->w_rflag |= WFMOVE;
1.23      kjell     183:        curwp->w_dotp = dlp;
                    184:        curwp->w_doto = getgoal(dlp);
                    185:
1.18      db        186:        return (TRUE);
1.1       deraadt   187: }
                    188:
                    189: /*
                    190:  * This function is like "forwline", but
                    191:  * goes backwards. The scheme is exactly the same.
                    192:  * Check for arguments that are less than zero and
                    193:  * call your alternate. Figure out the new line and
                    194:  * call "movedot" to perform the motion.
                    195:  */
1.3       millert   196: /* ARGSUSED */
                    197: int
1.12      vincent   198: backline(int f, int n)
1.1       deraadt   199: {
1.21      deraadt   200:        struct line   *dlp;
1.1       deraadt   201:
1.3       millert   202:        if (n < 0)
1.18      db        203:                return (forwline(f | FFRAND, -n));
1.14      vincent   204:        if ((lastflag & CFCPCN) == 0)   /* Fix goal. */
1.1       deraadt   205:                setgoal();
                    206:        thisflag |= CFCPCN;
                    207:        dlp = curwp->w_dotp;
1.25      kjell     208:        while (n-- && lback(dlp) != curbp->b_headp) {
1.1       deraadt   209:                dlp = lback(dlp);
1.23      kjell     210:                curwp->w_dotline--;
                    211:        }
1.3       millert   212:        curwp->w_dotp = dlp;
                    213:        curwp->w_doto = getgoal(dlp);
1.30      kjell     214:        curwp->w_rflag |= WFMOVE;
1.18      db        215:        return (TRUE);
1.1       deraadt   216: }
                    217:
                    218: /*
1.3       millert   219:  * Set the current goal column, which is saved in the external variable
                    220:  * "curgoal", to the current cursor column. The column is never off
                    221:  * the edge of the screen; it's more like display then show position.
1.1       deraadt   222:  */
1.6       art       223: void
1.12      vincent   224: setgoal(void)
1.3       millert   225: {
1.39      florian   226:        curgoal = getcolpos(curwp);     /* Get the position. */
1.3       millert   227:        /* we can now display past end of display, don't chop! */
1.1       deraadt   228: }
                    229:
                    230: /*
                    231:  * This routine looks at a line (pointed
                    232:  * to by the LINE pointer "dlp") and the current
                    233:  * vertical motion goal column (set by the "setgoal"
                    234:  * routine above) and returns the best offset to use
                    235:  * when a vertical motion is made into the line.
                    236:  */
1.3       millert   237: int
1.21      deraadt   238: getgoal(struct line *dlp)
1.3       millert   239: {
1.14      vincent   240:        int c, i, col = 0;
1.24      kjell     241:        char tmp[5];
                    242:
1.14      vincent   243:
                    244:        for (i = 0; i < llength(dlp); i++) {
                    245:                c = lgetc(dlp, i);
1.1       deraadt   246:                if (c == '\t'
                    247: #ifdef NOTAB
1.3       millert   248:                    && !(curbp->b_flag & BFNOTAB)
1.1       deraadt   249: #endif
1.14      vincent   250:                        ) {
                    251:                        col |= 0x07;
                    252:                        col++;
                    253:                } else if (ISCTRL(c) != FALSE) {
                    254:                        col += 2;
                    255:                } else if (isprint(c))
                    256:                        col++;
                    257:                else {
1.24      kjell     258:                        col += snprintf(tmp, sizeof(tmp), "\\%o", c);
1.14      vincent   259:                }
                    260:                if (col > curgoal)
1.1       deraadt   261:                        break;
                    262:        }
1.14      vincent   263:        return (i);
1.1       deraadt   264: }
                    265:
                    266: /*
                    267:  * Scroll forward by a specified number
                    268:  * of lines, or by a full page if no argument.
                    269:  * The "2" is the window overlap (this is the default
                    270:  * value from ITS EMACS). Because the top line in
                    271:  * the window is zapped, we have to do a hard
                    272:  * update and get it back.
                    273:  */
1.3       millert   274: /* ARGSUSED */
                    275: int
1.12      vincent   276: forwpage(int f, int n)
1.1       deraadt   277: {
1.21      deraadt   278:        struct line  *lp;
1.1       deraadt   279:
                    280:        if (!(f & FFARG)) {
1.3       millert   281:                n = curwp->w_ntrows - 2;        /* Default scroll.       */
                    282:                if (n <= 0)                     /* Forget the overlap    */
                    283:                        n = 1;                  /* if tiny window.       */
1.1       deraadt   284:        } else if (n < 0)
1.18      db        285:                return (backpage(f | FFRAND, -n));
1.31      lum       286:
1.1       deraadt   287:        lp = curwp->w_linep;
1.31      lum       288:        while (n--)
1.34      lum       289:                if ((lp = lforw(lp)) == curbp->b_headp) {
1.40    ! lum       290:                        dobeep();
1.34      lum       291:                        ewprintf("End of buffer");
1.31      lum       292:                        return(TRUE);
1.34      lum       293:                }
1.31      lum       294:
1.1       deraadt   295:        curwp->w_linep = lp;
1.30      kjell     296:        curwp->w_rflag |= WFFULL;
1.31      lum       297:
1.1       deraadt   298:        /* if in current window, don't move dot */
1.32      lum       299:        for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
1.3       millert   300:                if (lp == curwp->w_dotp)
1.18      db        301:                        return (TRUE);
1.31      lum       302:
1.27      kjell     303:        /* Advance the dot the slow way, for line nos */
                    304:        while (curwp->w_dotp != curwp->w_linep) {
                    305:                curwp->w_dotp = lforw(curwp->w_dotp);
                    306:                curwp->w_dotline++;
                    307:        }
1.3       millert   308:        curwp->w_doto = 0;
1.18      db        309:        return (TRUE);
1.1       deraadt   310: }
                    311:
                    312: /*
                    313:  * This command is like "forwpage",
                    314:  * but it goes backwards. The "2", like above,
                    315:  * is the overlap between the two windows. The
                    316:  * value is from the ITS EMACS manual. The
                    317:  * hard update is done because the top line in
                    318:  * the window is zapped.
                    319:  */
1.3       millert   320: /* ARGSUSED */
                    321: int
1.12      vincent   322: backpage(int f, int n)
1.1       deraadt   323: {
1.33      lum       324:        struct line  *lp, *lp2;
1.1       deraadt   325:
                    326:        if (!(f & FFARG)) {
1.3       millert   327:                n = curwp->w_ntrows - 2;        /* Default scroll.       */
                    328:                if (n <= 0)                     /* Don't blow up if the  */
1.35      lum       329:                        return (backline(f, 1));/* window is tiny.       */
1.1       deraadt   330:        } else if (n < 0)
1.18      db        331:                return (forwpage(f | FFRAND, -n));
1.33      lum       332:
                    333:        lp = lp2 = curwp->w_linep;
                    334:
1.25      kjell     335:        while (n-- && lback(lp) != curbp->b_headp) {
1.1       deraadt   336:                lp = lback(lp);
1.34      lum       337:        }
                    338:        if (lp == curwp->w_linep) {
1.40    ! lum       339:                dobeep();
1.34      lum       340:                ewprintf("Beginning of buffer");
1.23      kjell     341:        }
1.1       deraadt   342:        curwp->w_linep = lp;
1.30      kjell     343:        curwp->w_rflag |= WFFULL;
1.33      lum       344:
1.1       deraadt   345:        /* if in current window, don't move dot */
1.25      kjell     346:        for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
1.3       millert   347:                if (lp == curwp->w_dotp)
1.18      db        348:                        return (TRUE);
1.33      lum       349:
                    350:         lp2 = lforw(lp2);
                    351:
1.27      kjell     352:        /* Move the dot the slow way, for line nos */
1.33      lum       353:        while (curwp->w_dotp != lp2) {
1.36      lum       354:                 if (curwp->w_dotline <= curwp->w_ntrows)
                    355:                         return (TRUE);
1.27      kjell     356:                curwp->w_dotp = lback(curwp->w_dotp);
                    357:                curwp->w_dotline--;
                    358:        }
1.1       deraadt   359:        curwp->w_doto = 0;
1.18      db        360:        return (TRUE);
1.1       deraadt   361: }
                    362:
1.3       millert   363: /*
                    364:  * These functions are provided for compatibility with Gosling's Emacs. They
                    365:  * are used to scroll the display up (or down) one line at a time.
1.1       deraadt   366:  */
1.7       deraadt   367: int
1.12      vincent   368: forw1page(int f, int n)
1.1       deraadt   369: {
1.3       millert   370:        if (!(f & FFARG)) {
                    371:                n = 1;
1.1       deraadt   372:                f = FFUNIV;
                    373:        }
1.3       millert   374:        forwpage(f | FFRAND, n);
1.18      db        375:        return (TRUE);
1.1       deraadt   376: }
                    377:
1.7       deraadt   378: int
1.12      vincent   379: back1page(int f, int n)
1.1       deraadt   380: {
                    381:        if (!(f & FFARG)) {
1.3       millert   382:                n = 1;
1.1       deraadt   383:                f = FFUNIV;
                    384:        }
1.3       millert   385:        backpage(f | FFRAND, n);
1.18      db        386:        return (TRUE);
1.1       deraadt   387: }
                    388:
                    389: /*
                    390:  * Page the other window. Check to make sure it exists, then
                    391:  * nextwind, forwpage and restore window pointers.
                    392:  */
1.3       millert   393: int
1.12      vincent   394: pagenext(int f, int n)
1.1       deraadt   395: {
1.21      deraadt   396:        struct mgwin *wp;
1.1       deraadt   397:
                    398:        if (wheadp->w_wndp == NULL) {
                    399:                ewprintf("No other window");
1.18      db        400:                return (FALSE);
1.1       deraadt   401:        }
                    402:        wp = curwp;
1.6       art       403:        (void) nextwind(f, n);
                    404:        (void) forwpage(f, n);
1.1       deraadt   405:        curwp = wp;
                    406:        curbp = wp->w_bufp;
1.18      db        407:        return (TRUE);
1.1       deraadt   408: }
                    409:
                    410: /*
                    411:  * Internal set mark routine, used by other functions (daveb).
                    412:  */
1.6       art       413: void
1.12      vincent   414: isetmark(void)
1.1       deraadt   415: {
                    416:        curwp->w_markp = curwp->w_dotp;
                    417:        curwp->w_marko = curwp->w_doto;
1.23      kjell     418:        curwp->w_markline = curwp->w_dotline;
1.1       deraadt   419: }
                    420:
                    421: /*
                    422:  * Set the mark in the current window
                    423:  * to the value of dot. A message is written to
                    424:  * the echo line.  (ewprintf knows about macros)
                    425:  */
1.3       millert   426: /* ARGSUSED */
                    427: int
1.12      vincent   428: setmark(int f, int n)
1.1       deraadt   429: {
                    430:        isetmark();
                    431:        ewprintf("Mark set");
1.29      kjell     432:        return (TRUE);
                    433: }
                    434:
                    435: /* Clear the mark, if set. */
                    436: /* ARGSUSED */
                    437: int
                    438: clearmark(int f, int n)
                    439: {
                    440:        if (!curwp->w_markp)
                    441:                return (FALSE);
                    442:
                    443:        curwp->w_markp = NULL;
                    444:        curwp->w_marko = 0;
                    445:        curwp->w_markline = 0;
                    446:
1.18      db        447:        return (TRUE);
1.1       deraadt   448: }
                    449:
                    450: /*
                    451:  * Swap the values of "dot" and "mark" in
                    452:  * the current window. This is pretty easy, because
                    453:  * all of the hard work gets done by the standard routine
                    454:  * that moves the mark about. The only possible
                    455:  * error is "no mark".
                    456:  */
1.3       millert   457: /* ARGSUSED */
                    458: int
1.12      vincent   459: swapmark(int f, int n)
1.1       deraadt   460: {
1.21      deraadt   461:        struct line  *odotp;
1.23      kjell     462:        int odoto, odotline;
1.1       deraadt   463:
                    464:        if (curwp->w_markp == NULL) {
                    465:                ewprintf("No mark in this window");
1.18      db        466:                return (FALSE);
1.1       deraadt   467:        }
                    468:        odotp = curwp->w_dotp;
                    469:        odoto = curwp->w_doto;
1.23      kjell     470:        odotline = curwp->w_dotline;
1.3       millert   471:        curwp->w_dotp = curwp->w_markp;
                    472:        curwp->w_doto = curwp->w_marko;
1.23      kjell     473:        curwp->w_dotline = curwp->w_markline;
1.1       deraadt   474:        curwp->w_markp = odotp;
                    475:        curwp->w_marko = odoto;
1.23      kjell     476:        curwp->w_markline = odotline;
1.30      kjell     477:        curwp->w_rflag |= WFMOVE;
1.18      db        478:        return (TRUE);
1.1       deraadt   479: }
                    480:
                    481: /*
                    482:  * Go to a specific line, mostly for
                    483:  * looking up errors in C programs, which give the
                    484:  * error a line number. If an argument is present, then
                    485:  * it is the line number, else prompt for a line number
                    486:  * to use.
                    487:  */
1.3       millert   488: /* ARGSUSED */
                    489: int
1.12      vincent   490: gotoline(int f, int n)
1.1       deraadt   491: {
1.23      kjell     492:        char   buf[32], *bufp;
                    493:        const char *err;
1.1       deraadt   494:
                    495:        if (!(f & FFARG)) {
1.20      kjell     496:                if ((bufp = eread("Goto line: ", buf, sizeof(buf),
                    497:                    EFNUL | EFNEW | EFCR)) == NULL)
1.24      kjell     498:                        return (ABORT);
                    499:                if (bufp[0] == '\0')
1.18      db        500:                        return (ABORT);
1.23      kjell     501:                n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
                    502:                if (err) {
                    503:                        ewprintf("Line number %s", err);
1.18      db        504:                        return (FALSE);
1.9       vincent   505:                }
1.1       deraadt   506:        }
1.38      jasper    507:        return(setlineno(n));
                    508: }
                    509:
                    510: /*
                    511:  * Set the line number and switch to it.
                    512:  */
                    513: int
                    514: setlineno(int n)
                    515: {
                    516:        struct line  *clp;
                    517:
1.5       millert   518:        if (n >= 0) {
1.23      kjell     519:                if (n == 0)
                    520:                        n++;
                    521:                curwp->w_dotline = n;
1.25      kjell     522:                clp = lforw(curbp->b_headp);    /* "clp" is first line */
1.1       deraadt   523:                while (--n > 0) {
1.25      kjell     524:                        if (lforw(clp) == curbp->b_headp) {
1.23      kjell     525:                                curwp->w_dotline = curwp->w_bufp->b_lines;
1.3       millert   526:                                break;
1.23      kjell     527:                        }
1.1       deraadt   528:                        clp = lforw(clp);
                    529:                }
                    530:        } else {
1.23      kjell     531:                curwp->w_dotline = curwp->w_bufp->b_lines + n;
1.25      kjell     532:                clp = lback(curbp->b_headp);    /* "clp" is last line */
1.1       deraadt   533:                while (n < 0) {
1.25      kjell     534:                        if (lback(clp) == curbp->b_headp) {
1.23      kjell     535:                                curwp->w_dotline = 1;
1.3       millert   536:                                break;
1.23      kjell     537:                        }
1.1       deraadt   538:                        clp = lback(clp);
                    539:                        n++;
                    540:                }
                    541:        }
                    542:        curwp->w_dotp = clp;
                    543:        curwp->w_doto = 0;
1.30      kjell     544:        curwp->w_rflag |= WFMOVE;
1.18      db        545:        return (TRUE);
1.1       deraadt   546: }