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

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