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

Annotation of src/usr.bin/mg/paragraph.c, Revision 1.44

1.44    ! lum         1: /*     $OpenBSD: paragraph.c,v 1.43 2016/04/12 06:20:50 lum Exp $      */
1.11      kjell       2:
                      3: /* This file is in the public domain. */
1.4       niklas      4:
1.1       deraadt     5: /*
                      6:  * Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6
                      7:  * and GNU-ified by mwm@ucbvax.         Several bug fixes by blarson@usc-oberon.
                      8:  */
1.3       millert     9:
1.36      bcallah    10: #include <sys/queue.h>
1.24      lum        11: #include <ctype.h>
1.35      guenther   12: #include <limits.h>
1.36      bcallah    13: #include <signal.h>
                     14: #include <stdio.h>
                     15: #include <stdlib.h>
1.24      lum        16:
1.1       deraadt    17: #include "def.h"
                     18:
1.3       millert    19: static int     fillcol = 70;
                     20:
1.1       deraadt    21: #define MAXWORD 256
                     22:
1.37      lum        23: static int     findpara(void);
1.38      lum        24: static int     do_gotoeop(int, int, int *);
1.37      lum        25:
1.1       deraadt    26: /*
1.27      lum        27:  * Move to start of paragraph.
                     28:  * Move backwards by line, checking from the 1st character forwards for the
                     29:  * existence a non-space. If a non-space character is found, move to the
                     30:  * preceding line. Keep doing this until a line with only spaces is found or
                     31:  * the start of buffer.
1.1       deraadt    32:  */
1.2       millert    33: /* ARGSUSED */
1.3       millert    34: int
1.8       cloder     35: gotobop(int f, int n)
1.1       deraadt    36: {
1.26      lum        37:        int col, nospace;
1.24      lum        38:
1.3       millert    39:        /* the other way... */
                     40:        if (n < 0)
1.10      db         41:                return (gotoeop(f, -n));
1.1       deraadt    42:
1.3       millert    43:        while (n-- > 0) {
1.31      florian    44:                nospace = 0;
1.24      lum        45:                while (lback(curwp->w_dotp) != curbp->b_headp) {
                     46:                        curwp->w_doto = 0;
                     47:                        col = 0;
                     48:
                     49:                        while (col < llength(curwp->w_dotp) &&
                     50:                            (isspace(lgetc(curwp->w_dotp, col))))
                     51:                                col++;
                     52:
                     53:                        if (col >= llength(curwp->w_dotp)) {
                     54:                                if (nospace)
                     55:                                        break;
                     56:                        } else
                     57:                                nospace = 1;
1.32      lum        58:
                     59:                        curwp->w_dotline--;
                     60:                        curwp->w_dotp = lback(curwp->w_dotp);
1.24      lum        61:                }
1.1       deraadt    62:        }
1.3       millert    63:        /* force screen update */
1.19      kjell      64:        curwp->w_rflag |= WFMOVE;
1.10      db         65:        return (TRUE);
1.1       deraadt    66: }
                     67:
                     68: /*
1.27      lum        69:  * Move to end of paragraph.
                     70:  * See comments for gotobop(). Same, but moving forwards.
1.1       deraadt    71:  */
1.2       millert    72: /* ARGSUSED */
1.3       millert    73: int
1.8       cloder     74: gotoeop(int f, int n)
1.1       deraadt    75: {
1.38      lum        76:        int i;
                     77:
                     78:        return(do_gotoeop(f, n, &i));
                     79: }
                     80:
                     81: int
                     82: do_gotoeop(int f, int n, int *i)
                     83: {
                     84:        int col, nospace, j = 0;
1.25      lum        85:
1.3       millert    86:        /* the other way... */
                     87:        if (n < 0)
1.10      db         88:                return (gotobop(f, -n));
1.1       deraadt    89:
1.3       millert    90:        /* for each one asked for */
                     91:        while (n-- > 0) {
1.38      lum        92:                *i = ++j;
1.31      florian    93:                nospace = 0;
1.25      lum        94:                while (lforw(curwp->w_dotp) != curbp->b_headp) {
                     95:                        col = 0;
                     96:                        curwp->w_doto = 0;
                     97:
                     98:                        while (col < llength(curwp->w_dotp) &&
                     99:                            (isspace(lgetc(curwp->w_dotp, col))))
                    100:                                col++;
                    101:
                    102:                        if (col >= llength(curwp->w_dotp)) {
                    103:                                if (nospace)
                    104:                                        break;
1.23      lum       105:                        } else
1.25      lum       106:                                nospace = 1;
                    107:
                    108:                        curwp->w_dotp = lforw(curwp->w_dotp);
                    109:                        curwp->w_dotline++;
1.34      lum       110:
                    111:                        /* do not continue after end of buffer */
                    112:                        if (lforw(curwp->w_dotp) == curbp->b_headp) {
                    113:                                gotoeol(FFRAND, 1);
                    114:                                curwp->w_rflag |= WFMOVE;
                    115:                                return (FALSE);
                    116:                        }
1.1       deraadt   117:                }
                    118:        }
1.33      lum       119:
1.3       millert   120:        /* force screen update */
1.19      kjell     121:        curwp->w_rflag |= WFMOVE;
1.10      db        122:        return (TRUE);
1.1       deraadt   123: }
                    124:
                    125: /*
1.6       mickey    126:  * Justify a paragraph.  Fill the current paragraph according to the current
1.3       millert   127:  * fill column.
1.1       deraadt   128:  */
1.2       millert   129: /* ARGSUSED */
1.3       millert   130: int
1.8       cloder    131: fillpara(int f, int n)
1.1       deraadt   132: {
1.10      db        133:        int      c;             /* current char during scan             */
1.3       millert   134:        int      wordlen;       /* length of current word               */
                    135:        int      clength;       /* position on line during fill         */
                    136:        int      i;             /* index during word copy               */
                    137:        int      eopflag;       /* Are we at the End-Of-Paragraph?      */
                    138:        int      firstflag;     /* first word? (needs no space)         */
                    139:        int      newlength;     /* tentative new line length            */
                    140:        int      eolflag;       /* was at end of line                   */
1.12      kjell     141:        int      retval;        /* return value                         */
1.13      deraadt   142:        struct line     *eopline;       /* pointer to line just past EOP        */
1.3       millert   143:        char     wbuf[MAXWORD]; /* buffer for current word              */
1.1       deraadt   144:
1.41      lum       145:        if (n == 0)
                    146:                return (TRUE);
                    147:
1.17      kjell     148:        undo_boundary_enable(FFRAND, 0);
1.12      kjell     149:
1.1       deraadt   150:        /* record the pointer to the line just past the EOP */
1.5       art       151:        (void)gotoeop(FFRAND, 1);
1.2       millert   152:        if (curwp->w_doto != 0) {
1.1       deraadt   153:                /* paragraph ends at end of buffer */
1.5       art       154:                (void)lnewline();
1.1       deraadt   155:                eopline = lforw(curwp->w_dotp);
1.2       millert   156:        } else
                    157:                eopline = curwp->w_dotp;
1.1       deraadt   158:
1.42      mmcc      159:        /* and back top the beginning of the paragraph */
1.5       art       160:        (void)gotobop(FFRAND, 1);
1.1       deraadt   161:
                    162:        /* initialize various info */
1.9       avsm      163:        while (inword() == 0 && forwchar(FFRAND, 1));
1.3       millert   164:
1.1       deraadt   165:        clength = curwp->w_doto;
                    166:        wordlen = 0;
                    167:
                    168:        /* scan through lines, filling words */
                    169:        firstflag = TRUE;
                    170:        eopflag = FALSE;
                    171:        while (!eopflag) {
1.3       millert   172:
1.1       deraadt   173:                /* get the next character in the paragraph */
1.3       millert   174:                if ((eolflag = (curwp->w_doto == llength(curwp->w_dotp)))) {
1.1       deraadt   175:                        c = ' ';
                    176:                        if (lforw(curwp->w_dotp) == eopline)
                    177:                                eopflag = TRUE;
                    178:                } else
                    179:                        c = lgetc(curwp->w_dotp, curwp->w_doto);
                    180:
                    181:                /* and then delete it */
1.12      kjell     182:                if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag) {
                    183:                        retval = FALSE;
                    184:                        goto cleanup;
                    185:                }
1.1       deraadt   186:
                    187:                /* if not a separator, just add it in */
                    188:                if (c != ' ' && c != '\t') {
                    189:                        if (wordlen < MAXWORD - 1)
                    190:                                wbuf[wordlen++] = c;
                    191:                        else {
1.2       millert   192:                                /*
1.21      matthew   193:                                 * You lose chars beyond MAXWORD if the word
                    194:                                 * is too long. I'm too lazy to fix it now; it
1.2       millert   195:                                 * just silently truncated the word before,
                    196:                                 * so I get to feel smug.
1.1       deraadt   197:                                 */
                    198:                                ewprintf("Word too long!");
                    199:                        }
                    200:                } else if (wordlen) {
1.3       millert   201:
1.10      db        202:                        /* calculate tentative new length with word added */
1.1       deraadt   203:                        newlength = clength + 1 + wordlen;
1.3       millert   204:
1.2       millert   205:                        /*
                    206:                         * if at end of line or at doublespace and previous
1.1       deraadt   207:                         * character was one of '.','?','!' doublespace here.
1.20      lum       208:                         * behave the same way if a ')' is preceded by a
                    209:                         * [.?!] and followed by a doublespace.
1.1       deraadt   210:                         */
1.44    ! lum       211:                        if (dblspace && (!eopflag && ((eolflag ||
1.6       mickey    212:                            curwp->w_doto == llength(curwp->w_dotp) ||
1.3       millert   213:                            (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' '
1.20      lum       214:                            || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) ||
1.22      lum       215:                            (wbuf[wordlen - 1] == ')' && wordlen >= 2 &&
1.44    ! lum       216:                            ISEOSP(wbuf[wordlen - 2])))) &&
1.43      lum       217:                            wordlen < MAXWORD - 1))
1.1       deraadt   218:                                wbuf[wordlen++] = ' ';
1.3       millert   219:
1.1       deraadt   220:                        /* at a word break with a word waiting */
                    221:                        if (newlength <= fillcol) {
                    222:                                /* add word to current line */
                    223:                                if (!firstflag) {
1.5       art       224:                                        (void)linsert(1, ' ');
1.1       deraadt   225:                                        ++clength;
                    226:                                }
                    227:                                firstflag = FALSE;
                    228:                        } else {
1.2       millert   229:                                if (curwp->w_doto > 0 &&
                    230:                                    lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') {
1.1       deraadt   231:                                        curwp->w_doto -= 1;
1.5       art       232:                                        (void)ldelete((RSIZE) 1, KNONE);
1.1       deraadt   233:                                }
                    234:                                /* start a new line */
1.5       art       235:                                (void)lnewline();
1.1       deraadt   236:                                clength = 0;
                    237:                        }
                    238:
                    239:                        /* and add the word in in either case */
1.2       millert   240:                        for (i = 0; i < wordlen; i++) {
1.5       art       241:                                (void)linsert(1, wbuf[i]);
1.1       deraadt   242:                                ++clength;
                    243:                        }
                    244:                        wordlen = 0;
                    245:                }
                    246:        }
                    247:        /* and add a last newline for the end of our new paragraph */
1.5       art       248:        (void)lnewline();
1.3       millert   249:
1.2       millert   250:        /*
1.10      db        251:         * We really should wind up where we started, (which is hard to keep
1.1       deraadt   252:         * track of) but I think the end of the last line is better than the
1.10      db        253:         * beginning of the blank line.
1.2       millert   254:         */
1.5       art       255:        (void)backchar(FFRAND, 1);
1.12      kjell     256:        retval = TRUE;
                    257: cleanup:
1.17      kjell     258:        undo_boundary_enable(FFRAND, 1);
1.12      kjell     259:        return (retval);
1.1       deraadt   260: }
                    261:
1.6       mickey    262: /*
1.39      lum       263:  * Delete n paragraphs. Move to the beginning of the current paragraph, or if
                    264:  * the cursor is on an empty line, move down the buffer to the first line with
                    265:  * non-space characters. Then mark n paragraphs and delete.
1.3       millert   266:  */
1.2       millert   267: /* ARGSUSED */
1.3       millert   268: int
1.8       cloder    269: killpara(int f, int n)
1.1       deraadt   270: {
1.37      lum       271:        int     lineno, status;
                    272:
1.41      lum       273:        if (n == 0)
                    274:                return (TRUE);
                    275:
1.37      lum       276:        if (findpara() == FALSE)
                    277:                return (TRUE);
                    278:
                    279:        /* go to the beginning of the paragraph */
                    280:        (void)gotobop(FFRAND, 1);
1.1       deraadt   281:
1.37      lum       282:        /* take a note of the line number for after deletions and set mark */
                    283:        lineno = curwp->w_dotline;
                    284:        curwp->w_markp = curwp->w_dotp;
                    285:        curwp->w_marko = curwp->w_doto;
1.1       deraadt   286:
1.37      lum       287:        (void)gotoeop(FFRAND, n);
1.1       deraadt   288:
1.37      lum       289:        if ((status = killregion(FFRAND, 1)) != TRUE)
                    290:                return (status);
1.1       deraadt   291:
1.37      lum       292:        curwp->w_dotline = lineno;
1.38      lum       293:        return (TRUE);
                    294: }
                    295:
                    296: /*
1.39      lum       297:  * Mark n paragraphs starting with the n'th and working our way backwards.
1.38      lum       298:  * This leaves the cursor at the beginning of the paragraph where markpara()
                    299:  * was invoked.
                    300:  */
                    301: /* ARGSUSED */
                    302: int
                    303: markpara(int f, int n)
                    304: {
                    305:        int i = 0;
                    306:
1.41      lum       307:        if (n == 0)
                    308:                return (TRUE);
                    309:
1.38      lum       310:        clearmark(FFARG, 0);
                    311:
                    312:        if (findpara() == FALSE)
                    313:                return (TRUE);
                    314:
                    315:        (void)do_gotoeop(FFRAND, n, &i);
                    316:
                    317:        /* set the mark here */
                    318:        curwp->w_markp = curwp->w_dotp;
                    319:        curwp->w_marko = curwp->w_doto;
                    320:
                    321:        (void)gotobop(FFRAND, i);
1.40      lum       322:
                    323:        return (TRUE);
                    324: }
                    325:
                    326: /*
                    327:  * Transpose the current paragraph with the following paragraph. If invoked
                    328:  * multiple times, transpose to the n'th paragraph. If invoked between
                    329:  * paragraphs, move to the previous paragraph, then continue.
                    330:  */
                    331: /* ARGSUSED */
                    332: int
                    333: transposepara(int f, int n)
                    334: {
                    335:        int     i = 0, status;
                    336:        char    flg;
1.41      lum       337:
                    338:        if (n == 0)
                    339:                return (TRUE);
1.40      lum       340:
                    341:        /* find a paragraph, set mark, then goto the end */
                    342:        gotobop(FFRAND, 1);
                    343:        curwp->w_markp = curwp->w_dotp;
                    344:        curwp->w_marko = curwp->w_doto;
                    345:        (void)gotoeop(FFRAND, 1);
                    346:
                    347:        /* take a note of buffer flags - we may need them */
                    348:        flg = curbp->b_flag;
                    349:
                    350:        /* clean out kill buffer then kill region */
                    351:        kdelete();
                    352:        if ((status = killregion(FFRAND, 1)) != TRUE)
                    353:                return (status);
                    354:
                    355:        /*
                    356:         * Now step through n paragraphs. If we reach the end of buffer,
                    357:         * stop and paste the killed region back, then display a message.
                    358:         */
                    359:        if (do_gotoeop(FFRAND, n, &i) == FALSE) {
                    360:                ewprintf("Cannot transpose paragraph, end of buffer reached.");
                    361:                (void)gotobop(FFRAND, i);
                    362:                (void)yank(FFRAND, 1);
                    363:                curbp->b_flag = flg;
                    364:                return (FALSE);
                    365:        }
                    366:        (void)yank(FFRAND, 1);
1.38      lum       367:
1.37      lum       368:        return (TRUE);
                    369: }
                    370:
                    371: /*
1.39      lum       372:  * Go down the buffer until we find a line with non-space characters.
1.37      lum       373:  */
                    374: int
                    375: findpara(void)
                    376: {
                    377:        int     col, nospace = 0;
1.3       millert   378:
1.37      lum       379:        /* we move forward to find a para to mark */
                    380:        do {
1.3       millert   381:                curwp->w_doto = 0;
1.37      lum       382:                col = 0;
                    383:
                    384:                /* check if we are on a blank line */
                    385:                while (col < llength(curwp->w_dotp)) {
                    386:                        if (!isspace(lgetc(curwp->w_dotp, col)))
                    387:                                nospace = 1;
                    388:                        col++;
                    389:                }
                    390:                if (nospace)
                    391:                        break;
1.1       deraadt   392:
1.37      lum       393:                if (lforw(curwp->w_dotp) == curbp->b_headp)
                    394:                        return (FALSE);
                    395:
                    396:                curwp->w_dotp = lforw(curwp->w_dotp);
                    397:                curwp->w_dotline++;
                    398:        } while (1);
1.34      lum       399:
1.10      db        400:        return (TRUE);
1.1       deraadt   401: }
                    402:
                    403: /*
1.3       millert   404:  * Insert char with work wrap.  Check to see if we're past fillcol, and if so,
                    405:  * justify this line.  As a last step, justify the line.
1.1       deraadt   406:  */
1.2       millert   407: /* ARGSUSED */
1.3       millert   408: int
1.8       cloder    409: fillword(int f, int n)
1.1       deraadt   410: {
1.3       millert   411:        char    c;
                    412:        int     col, i, nce;
1.1       deraadt   413:
                    414:        for (i = col = 0; col <= fillcol; ++i, ++col) {
1.2       millert   415:                if (i == curwp->w_doto)
                    416:                        return selfinsert(f, n);
1.1       deraadt   417:                c = lgetc(curwp->w_dotp, i);
                    418:                if (c == '\t'
1.3       millert   419: #ifdef NOTAB
1.2       millert   420:                    && !(curbp->b_flag & BFNOTAB)
1.1       deraadt   421: #endif
1.2       millert   422:                        )
                    423:                        col |= 0x07;
                    424:                else if (ISCTRL(c) != FALSE)
                    425:                        ++col;
1.1       deraadt   426:        }
                    427:        if (curwp->w_doto != llength(curwp->w_dotp)) {
1.5       art       428:                (void)selfinsert(f, n);
1.1       deraadt   429:                nce = llength(curwp->w_dotp) - curwp->w_doto;
1.2       millert   430:        } else
                    431:                nce = 0;
1.1       deraadt   432:        curwp->w_doto = i;
                    433:
                    434:        if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
                    435:                do {
1.5       art       436:                        (void)backchar(FFRAND, 1);
1.7       deraadt   437:                } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
                    438:                    c != '\t' && curwp->w_doto > 0);
1.1       deraadt   439:
                    440:        if (curwp->w_doto == 0)
                    441:                do {
1.5       art       442:                        (void)forwchar(FFRAND, 1);
1.7       deraadt   443:                } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
                    444:                    c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
1.1       deraadt   445:
1.5       art       446:        (void)delwhite(FFRAND, 1);
                    447:        (void)lnewline();
1.1       deraadt   448:        i = llength(curwp->w_dotp) - nce;
1.2       millert   449:        curwp->w_doto = i > 0 ? i : 0;
1.19      kjell     450:        curwp->w_rflag |= WFMOVE;
1.2       millert   451:        if (nce == 0 && curwp->w_doto != 0)
1.10      db        452:                return (fillword(f, n));
                    453:        return (TRUE);
1.1       deraadt   454: }
                    455:
1.3       millert   456: /*
                    457:  * Set fill column to n for justify.
                    458:  */
                    459: int
1.8       cloder    460: setfillcol(int f, int n)
1.2       millert   461: {
1.16      kjell     462:        char buf[32], *rep;
                    463:        const char *es;
1.18      kjell     464:        int nfill;
1.16      kjell     465:
                    466:        if ((f & FFARG) != 0) {
                    467:                fillcol = n;
                    468:        } else {
                    469:                if ((rep = eread("Set fill-column: ", buf, sizeof(buf),
                    470:                    EFNEW | EFCR)) == NULL)
                    471:                        return (ABORT);
                    472:                else if (rep[0] == '\0')
                    473:                        return (FALSE);
1.18      kjell     474:                nfill = strtonum(rep, 0, INT_MAX, &es);
                    475:                if (es != NULL) {
1.30      lum       476:                        dobeep();
1.18      kjell     477:                        ewprintf("Invalid fill column: %s", rep);
1.16      kjell     478:                        return (FALSE);
1.18      kjell     479:                }
                    480:                fillcol = nfill;
1.16      kjell     481:                ewprintf("Fill column set to %d", fillcol);
                    482:        }
1.44    ! lum       483:        return (TRUE);
        !           484: }
        !           485:
        !           486: int
        !           487: sentencespace(int f, int n)
        !           488: {
        !           489:        if (f & FFARG)
        !           490:                dblspace = n > 1;
        !           491:        else
        !           492:                dblspace = !dblspace;
        !           493:
1.10      db        494:        return (TRUE);
1.1       deraadt   495: }