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

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

1.39      lum         1: /*     $OpenBSD: util.c,v 1.38 2015/11/18 18:21:06 jasper Exp $        */
1.12      kjell       2:
                      3: /* This file is in the public domain. */
1.4       niklas      4:
1.1       deraadt     5: /*
                      6:  *             Assorted commands.
1.6       mickey      7:  * This file contains the command processors for a large assortment of
                      8:  * unrelated commands.  The only thing they have in common is that they
1.3       millert     9:  * are all command processors.
                     10:  */
                     11:
1.35      bcallah    12: #include <sys/queue.h>
                     13: #include <ctype.h>
                     14: #include <signal.h>
                     15: #include <stdio.h>
                     16:
1.3       millert    17: #include "def.h"
1.1       deraadt    18:
                     19: /*
1.6       mickey     20:  * Display a bunch of useful information about the current location of dot.
                     21:  * The character under the cursor (in octal), the current line, row, and
                     22:  * column, and approximate position of the cursor in the file (as a
                     23:  * percentage) is displayed.  The column position assumes an infinite
1.3       millert    24:  * position display; it does not truncate just because the screen does.
1.1       deraadt    25:  * This is normally bound to "C-X =".
                     26:  */
1.2       millert    27: /* ARGSUSED */
1.3       millert    28: int
1.10      cloder     29: showcpos(int f, int n)
1.1       deraadt    30: {
1.15      deraadt    31:        struct line     *clp;
1.11      db         32:        long     nchar, cchar;
1.3       millert    33:        int      nline, row;
                     34:        int      cline, cbyte;          /* Current line/char/byte */
                     35:        int      ratio;
                     36:
                     37:        /* collect the data */
1.22      kjell      38:        clp = bfirstlp(curbp);
1.3       millert    39:        cchar = 0;
                     40:        cline = 0;
                     41:        cbyte = 0;
1.1       deraadt    42:        nchar = 0;
                     43:        nline = 0;
1.6       mickey     44:        for (;;) {
1.3       millert    45:                /* count this line */
                     46:                ++nline;
1.1       deraadt    47:                if (clp == curwp->w_dotp) {
1.3       millert    48:                        /* mark line */
                     49:                        cline = nline;
1.1       deraadt    50:                        cchar = nchar + curwp->w_doto;
                     51:                        if (curwp->w_doto == llength(clp))
                     52:                                cbyte = '\n';
                     53:                        else
                     54:                                cbyte = lgetc(clp, curwp->w_doto);
                     55:                }
1.3       millert    56:                /* now count the chars */
                     57:                nchar += llength(clp);
1.1       deraadt    58:                clp = lforw(clp);
1.21      kjell      59:                if (clp == curbp->b_headp)
1.2       millert    60:                        break;
1.3       millert    61:                /* count the newline */
                     62:                nchar++;
1.1       deraadt    63:        }
1.3       millert    64:        /* determine row */
                     65:        row = curwp->w_toprow + 1;
1.1       deraadt    66:        clp = curwp->w_linep;
1.21      kjell      67:        while (clp != curbp->b_headp && clp != curwp->w_dotp) {
1.1       deraadt    68:                ++row;
                     69:                clp = lforw(clp);
                     70:        }
1.2       millert    71:        ratio = nchar ? (100L * cchar) / nchar : 100;
1.1       deraadt    72:        ewprintf("Char: %c (0%o)  point=%ld(%d%%)  line=%d  row=%d  col=%d",
1.32      florian    73:            cbyte, cbyte, cchar, ratio, cline, row, getcolpos(curwp));
1.11      db         74:        return (TRUE);
1.1       deraadt    75: }
                     76:
1.3       millert    77: int
1.32      florian    78: getcolpos(struct mgwin *wp)
1.2       millert    79: {
1.3       millert    80:        int     col, i, c;
1.20      kjell      81:        char tmp[5];
1.3       millert    82:
                     83:        /* determine column */
1.9       vincent    84:        col = 0;
1.1       deraadt    85:
1.32      florian    86:        for (i = 0; i < wp->w_doto; ++i) {
                     87:                c = lgetc(wp->w_dotp, i);
1.1       deraadt    88:                if (c == '\t'
1.3       millert    89: #ifdef NOTAB
1.32      florian    90:                    && !(wp->w_bufp->b_flag & BFNOTAB)
1.3       millert    91: #endif /* NOTAB */
1.1       deraadt    92:                        ) {
1.2       millert    93:                        col |= 0x07;
1.9       vincent    94:                        col++;
1.1       deraadt    95:                } else if (ISCTRL(c) != FALSE)
1.9       vincent    96:                        col += 2;
1.20      kjell      97:                else if (isprint(c)) {
1.9       vincent    98:                        col++;
1.20      kjell      99:                } else {
                    100:                        col += snprintf(tmp, sizeof(tmp), "\\%o", c);
1.9       vincent   101:                }
                    102:
1.1       deraadt   103:        }
1.11      db        104:        return (col);
1.1       deraadt   105: }
1.3       millert   106:
1.1       deraadt   107: /*
1.33      lum       108:  * Twiddle the two characters in front of and under dot, then move forward
                    109:  * one character.  Treat new-line characters the same as any other.
                    110:  * Normally bound to "C-t".  This always works within a line, so "WFEDIT"
1.3       millert   111:  * is good enough.
1.1       deraadt   112:  */
1.2       millert   113: /* ARGSUSED */
1.3       millert   114: int
1.10      cloder    115: twiddle(int f, int n)
1.1       deraadt   116: {
1.15      deraadt   117:        struct line     *dotp;
1.3       millert   118:        int      doto, cr;
1.37      lum       119:
                    120:        if (n == 0)
                    121:                return (TRUE);
1.1       deraadt   122:
                    123:        dotp = curwp->w_dotp;
                    124:        doto = curwp->w_doto;
1.33      lum       125:
                    126:        /* Don't twiddle if the dot is on the first char of buffer */
                    127:        if (doto == 0 && lback(dotp) == curbp->b_headp) {
                    128:                dobeep();
                    129:                ewprintf("Beginning of buffer");
                    130:                return(FALSE);
                    131:        }
                    132:        /* Don't twiddle if the dot is on the last char of buffer */
                    133:        if (doto == llength(dotp) && lforw(dotp) == curbp->b_headp) {
                    134:                dobeep();
                    135:                return(FALSE);
                    136:        }
                    137:        undo_boundary_enable(FFRAND, 0);
                    138:        if (doto == 0 && doto == llength(dotp)) { /* only '\n' on this line */
                    139:                (void)forwline(FFRAND, 1);
                    140:                curwp->w_doto = 0;
1.1       deraadt   141:        } else {
1.33      lum       142:                if (doto == 0) { /* 1st twiddle is on 1st character of a line */
                    143:                        cr = lgetc(dotp, doto);
                    144:                        (void)backdel(FFRAND, 1);
                    145:                        (void)forwchar(FFRAND, 1);
                    146:                        lnewline();
                    147:                        linsert(1, cr);
                    148:                        (void)backdel(FFRAND, 1);
1.38      jasper    149:                } else {        /* twiddle is elsewhere in line */
1.33      lum       150:                        cr = lgetc(dotp, doto - 1);
                    151:                        (void)backdel(FFRAND, 1);
                    152:                        (void)forwchar(FFRAND, 1);
                    153:                        linsert(1, cr);
                    154:                }
1.1       deraadt   155:        }
1.26      kjell     156:        undo_boundary_enable(FFRAND, 1);
1.1       deraadt   157:        lchange(WFEDIT);
1.11      db        158:        return (TRUE);
1.1       deraadt   159: }
                    160:
                    161: /*
1.6       mickey    162:  * Open up some blank space.  The basic plan is to insert a bunch of
                    163:  * newlines, and then back up over them.  Everything is done by the
1.11      db        164:  * subcommand processors.  They even handle the looping.  Normally this
1.3       millert   165:  * is bound to "C-O".
1.1       deraadt   166:  */
1.2       millert   167: /* ARGSUSED */
1.3       millert   168: int
1.10      cloder    169: openline(int f, int n)
1.1       deraadt   170: {
1.11      db        171:        int     i, s;
1.1       deraadt   172:
                    173:        if (n < 0)
1.11      db        174:                return (FALSE);
1.1       deraadt   175:        if (n == 0)
1.11      db        176:                return (TRUE);
1.3       millert   177:
                    178:        /* insert newlines */
1.29      kjell     179:        undo_boundary_enable(FFRAND, 0);
1.3       millert   180:        i = n;
1.1       deraadt   181:        do {
                    182:                s = lnewline();
1.2       millert   183:        } while (s == TRUE && --i);
1.3       millert   184:
                    185:        /* then go back up overtop of them all */
                    186:        if (s == TRUE)
                    187:                s = backchar(f | FFRAND, n);
1.29      kjell     188:        undo_boundary_enable(FFRAND, 1);
1.11      db        189:        return (s);
1.1       deraadt   190: }
                    191:
                    192: /*
1.14      kjell     193:  * Insert a newline.
1.1       deraadt   194:  */
1.2       millert   195: /* ARGSUSED */
1.3       millert   196: int
1.34      bcallah   197: enewline(int f, int n)
1.1       deraadt   198: {
1.3       millert   199:        int      s;
1.1       deraadt   200:
1.2       millert   201:        if (n < 0)
1.11      db        202:                return (FALSE);
1.3       millert   203:
1.1       deraadt   204:        while (n--) {
1.2       millert   205:                if ((s = lnewline()) != TRUE)
1.11      db        206:                        return (s);
1.1       deraadt   207:        }
1.11      db        208:        return (TRUE);
1.1       deraadt   209: }
                    210:
                    211: /*
1.3       millert   212:  * Delete blank lines around dot. What this command does depends if dot is
1.6       mickey    213:  * sitting on a blank line. If dot is sitting on a blank line, this command
                    214:  * deletes all the blank lines above and below the current line. If it is
                    215:  * sitting on a non blank line then it deletes all of the blank lines after
                    216:  * the line. Normally this command is bound to "C-X C-O". Any argument is
1.3       millert   217:  * ignored.
1.1       deraadt   218:  */
1.2       millert   219: /* ARGSUSED */
1.3       millert   220: int
1.10      cloder    221: deblank(int f, int n)
1.1       deraadt   222: {
1.15      deraadt   223:        struct line     *lp1, *lp2;
1.3       millert   224:        RSIZE    nld;
1.1       deraadt   225:
                    226:        lp1 = curwp->w_dotp;
1.21      kjell     227:        while (llength(lp1) == 0 && (lp2 = lback(lp1)) != curbp->b_headp)
1.1       deraadt   228:                lp1 = lp2;
                    229:        lp2 = lp1;
1.3       millert   230:        nld = (RSIZE)0;
1.21      kjell     231:        while ((lp2 = lforw(lp2)) != curbp->b_headp && llength(lp2) == 0)
1.1       deraadt   232:                ++nld;
                    233:        if (nld == 0)
                    234:                return (TRUE);
                    235:        curwp->w_dotp = lforw(lp1);
                    236:        curwp->w_doto = 0;
1.11      db        237:        return (ldelete((RSIZE)nld, KNONE));
1.1       deraadt   238: }
                    239:
                    240: /*
                    241:  * Delete any whitespace around dot, then insert a space.
                    242:  */
1.3       millert   243: int
1.10      cloder    244: justone(int f, int n)
1.2       millert   245: {
1.29      kjell     246:        undo_boundary_enable(FFRAND, 0);
1.5       art       247:        (void)delwhite(f, n);
1.29      kjell     248:        linsert(1, ' ');
                    249:        undo_boundary_enable(FFRAND, 1);
                    250:        return (TRUE);
1.1       deraadt   251: }
1.3       millert   252:
1.1       deraadt   253: /*
                    254:  * Delete any whitespace around dot.
                    255:  */
1.2       millert   256: /* ARGSUSED */
1.3       millert   257: int
1.10      cloder    258: delwhite(int f, int n)
1.1       deraadt   259: {
1.25      kjell     260:        int     col, s;
1.1       deraadt   261:
                    262:        col = curwp->w_doto;
1.3       millert   263:
1.8       vincent   264:        while (col < llength(curwp->w_dotp) &&
1.25      kjell     265:            (isspace(lgetc(curwp->w_dotp, col))))
1.1       deraadt   266:                ++col;
                    267:        do {
                    268:                if (curwp->w_doto == 0) {
                    269:                        s = FALSE;
                    270:                        break;
                    271:                }
1.2       millert   272:                if ((s = backchar(FFRAND, 1)) != TRUE)
                    273:                        break;
1.25      kjell     274:        } while (isspace(lgetc(curwp->w_dotp, curwp->w_doto)));
1.1       deraadt   275:
1.2       millert   276:        if (s == TRUE)
1.5       art       277:                (void)forwchar(FFRAND, 1);
                    278:        (void)ldelete((RSIZE)(col - curwp->w_doto), KNONE);
1.11      db        279:        return (TRUE);
1.1       deraadt   280: }
1.3       millert   281:
1.1       deraadt   282: /*
1.25      kjell     283:  * Delete any leading whitespace on the current line
                    284:  */
                    285: int
                    286: delleadwhite(int f, int n)
                    287: {
                    288:        int soff, ls;
                    289:        struct line *slp;
                    290:
                    291:        /* Save current position */
                    292:        slp = curwp->w_dotp;
                    293:        soff = curwp->w_doto;
                    294:
                    295:        for (ls = 0; ls < llength(slp); ls++)
                    296:                  if (!isspace(lgetc(slp, ls)))
                    297:                         break;
                    298:        gotobol(FFRAND, 1);
                    299:        forwdel(FFRAND, ls);
                    300:        soff -= ls;
                    301:        if (soff < 0)
                    302:                soff = 0;
                    303:        forwchar(FFRAND, soff);
                    304:
                    305:        return (TRUE);
                    306: }
                    307:
                    308: /*
                    309:  * Delete any trailing whitespace on the current line
                    310:  */
                    311: int
                    312: deltrailwhite(int f, int n)
                    313: {
                    314:        int soff;
                    315:
                    316:        /* Save current position */
                    317:        soff = curwp->w_doto;
                    318:
                    319:        gotoeol(FFRAND, 1);
                    320:        delwhite(FFRAND, 1);
                    321:
                    322:        /* restore original position, if possible */
                    323:        if (soff < curwp->w_doto)
                    324:                curwp->w_doto = soff;
                    325:
                    326:        return (TRUE);
                    327: }
                    328:
                    329:
                    330:
                    331: /*
1.3       millert   332:  * Insert a newline, then enough tabs and spaces to duplicate the indentation
1.6       mickey    333:  * of the previous line.  Assumes tabs are every eight characters.  Quite
                    334:  * simple.  Figure out the indentation of the current line.  Insert a newline
                    335:  * by calling the standard routine.  Insert the indentation by inserting the
                    336:  * right number of tabs and spaces.  Return TRUE if all ok.  Return FALSE if
1.24      kjell     337:  * one of the subcommands failed. Normally bound to "C-M".
1.1       deraadt   338:  */
1.2       millert   339: /* ARGSUSED */
1.3       millert   340: int
1.25      kjell     341: lfindent(int f, int n)
1.1       deraadt   342: {
1.11      db        343:        int     c, i, nicol;
1.29      kjell     344:        int     s = TRUE;
1.1       deraadt   345:
1.2       millert   346:        if (n < 0)
                    347:                return (FALSE);
1.3       millert   348:
1.29      kjell     349:        undo_boundary_enable(FFRAND, 0);
1.1       deraadt   350:        while (n--) {
                    351:                nicol = 0;
1.2       millert   352:                for (i = 0; i < llength(curwp->w_dotp); ++i) {
1.1       deraadt   353:                        c = lgetc(curwp->w_dotp, i);
1.2       millert   354:                        if (c != ' ' && c != '\t')
1.1       deraadt   355:                                break;
                    356:                        if (c == '\t')
                    357:                                nicol |= 0x07;
                    358:                        ++nicol;
                    359:                }
                    360:                if (lnewline() == FALSE || ((
                    361: #ifdef NOTAB
1.3       millert   362:                    curbp->b_flag & BFNOTAB) ? linsert(nicol, ' ') == FALSE : (
                    363: #endif /* NOTAB */
                    364:                    ((i = nicol / 8) != 0 && linsert(i, '\t') == FALSE) ||
1.29      kjell     365:                    ((i = nicol % 8) != 0 && linsert(i, ' ') == FALSE)))) {
                    366:                        s = FALSE;
                    367:                        break;
                    368:                }
1.1       deraadt   369:        }
1.29      kjell     370:        undo_boundary_enable(FFRAND, 1);
                    371:        return (s);
1.1       deraadt   372: }
1.25      kjell     373:
                    374: /*
                    375:  * Indent the current line. Delete existing leading whitespace,
                    376:  * and use tabs/spaces to achieve correct indentation. Try
                    377:  * to leave dot where it started.
                    378:  */
                    379: int
                    380: indent(int f, int n)
                    381: {
                    382:        int soff, i;
                    383:
                    384:        if (n < 0)
                    385:                return (FALSE);
                    386:
                    387:        delleadwhite(FFRAND, 1);
                    388:
                    389:        /* If not invoked with a numerical argument, done */
                    390:        if (!(f & FFARG))
                    391:                return (TRUE);
                    392:
                    393:        /* insert appropriate whitespace */
                    394:        soff = curwp->w_doto;
                    395:        (void)gotobol(FFRAND, 1);
                    396:        if (
                    397: #ifdef NOTAB
1.31      lum       398:            (curbp->b_flag & BFNOTAB) ? linsert(n, ' ') == FALSE :
1.25      kjell     399: #endif /* NOTAB */
                    400:            (((i = n / 8) != 0 && linsert(i, '\t') == FALSE) ||
                    401:            ((i = n % 8) != 0 && linsert(i, ' ') == FALSE)))
                    402:                return (FALSE);
                    403:
                    404:        forwchar(FFRAND, soff);
                    405:
                    406:        return (TRUE);
                    407: }
                    408:
1.1       deraadt   409:
                    410: /*
1.3       millert   411:  * Delete forward.  This is real easy, because the basic delete routine does
1.6       mickey    412:  * all of the work.  Watches for negative arguments, and does the right thing.
                    413:  * If any argument is present, it kills rather than deletes, to prevent loss
1.40    ! phessler  414:  * of text if typed with a big argument.  Normally bound to "C-D".
1.1       deraadt   415:  */
1.2       millert   416: /* ARGSUSED */
1.3       millert   417: int
1.10      cloder    418: forwdel(int f, int n)
1.1       deraadt   419: {
                    420:        if (n < 0)
1.11      db        421:                return (backdel(f | FFRAND, -n));
1.3       millert   422:
                    423:        /* really a kill */
                    424:        if (f & FFARG) {
1.2       millert   425:                if ((lastflag & CFKILL) == 0)
1.1       deraadt   426:                        kdelete();
                    427:                thisflag |= CFKILL;
                    428:        }
1.3       millert   429:
1.11      db        430:        return (ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE));
1.1       deraadt   431: }
                    432:
                    433: /*
1.6       mickey    434:  * Delete backwards.  This is quite easy too, because it's all done with
                    435:  * other functions.  Just move the cursor back, and delete forwards.  Like
1.3       millert   436:  * delete forward, this actually does a kill if presented with an argument.
1.1       deraadt   437:  */
1.2       millert   438: /* ARGSUSED */
1.3       millert   439: int
1.10      cloder    440: backdel(int f, int n)
1.1       deraadt   441: {
1.3       millert   442:        int     s;
1.1       deraadt   443:
                    444:        if (n < 0)
1.11      db        445:                return (forwdel(f | FFRAND, -n));
1.3       millert   446:
                    447:        /* really a kill */
                    448:        if (f & FFARG) {
1.2       millert   449:                if ((lastflag & CFKILL) == 0)
1.1       deraadt   450:                        kdelete();
                    451:                thisflag |= CFKILL;
                    452:        }
1.2       millert   453:        if ((s = backchar(f | FFRAND, n)) == TRUE)
1.3       millert   454:                s = ldelete((RSIZE)n, (f & FFARG) ? KFORW : KNONE);
                    455:
1.11      db        456:        return (s);
1.1       deraadt   457: }
                    458:
                    459: #ifdef NOTAB
1.2       millert   460: /* ARGSUSED */
1.3       millert   461: int
1.10      cloder    462: space_to_tabstop(int f, int n)
1.1       deraadt   463: {
1.2       millert   464:        if (n < 0)
1.11      db        465:                return (FALSE);
1.2       millert   466:        if (n == 0)
1.11      db        467:                return (TRUE);
                    468:        return (linsert((n << 3) - (curwp->w_doto & 7), ' '));
1.1       deraadt   469: }
1.3       millert   470: #endif /* NOTAB */
1.27      kjell     471:
                    472: /*
                    473:  * Move the dot to the first non-whitespace character of the current line.
                    474:  */
                    475: int
                    476: backtoindent(int f, int n)
                    477: {
                    478:        gotobol(FFRAND, 1);
                    479:        while (curwp->w_doto < llength(curwp->w_dotp) &&
                    480:            (isspace(lgetc(curwp->w_dotp, curwp->w_doto))))
                    481:                ++curwp->w_doto;
1.28      kjell     482:        return (TRUE);
                    483: }
                    484:
                    485: /*
                    486:  * Join the current line to the previous, or with arg, the next line
                    487:  * to the current one.  If the former line is not empty, leave exactly
                    488:  * one space at the joint.  Otherwise, leave no whitespace.
                    489:  */
                    490: int
                    491: joinline(int f, int n)
                    492: {
                    493:        int doto;
                    494:
                    495:        undo_boundary_enable(FFRAND, 0);
                    496:        if (f & FFARG) {
                    497:                gotoeol(FFRAND, 1);
                    498:                forwdel(FFRAND, 1);
                    499:        } else {
                    500:                gotobol(FFRAND, 1);
                    501:                backdel(FFRAND, 1);
                    502:        }
                    503:
                    504:        delwhite(FFRAND, 1);
                    505:
                    506:        if ((doto = curwp->w_doto) > 0) {
                    507:                linsert(1, ' ');
                    508:                curwp->w_doto = doto;
                    509:        }
                    510:        undo_boundary_enable(FFRAND, 1);
                    511:
1.27      kjell     512:        return (TRUE);
                    513: }