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

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