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

1.22    ! lum         1: /*     $OpenBSD: paragraph.c,v 1.21 2011/11/28 23:37:32 matthew 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.1       deraadt    10: #include "def.h"
                     11:
1.3       millert    12: static int     fillcol = 70;
                     13:
1.1       deraadt    14: #define MAXWORD 256
                     15:
                     16: /*
1.10      db         17:  * Move to start of paragraph.  Go back to the beginning of the current
1.6       mickey     18:  * paragraph here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
1.10      db         19:  * combination to delimit the beginning of a paragraph.
1.1       deraadt    20:  */
1.2       millert    21: /* ARGSUSED */
1.3       millert    22: int
1.8       cloder     23: gotobop(int f, int n)
1.1       deraadt    24: {
1.3       millert    25:        /* the other way... */
                     26:        if (n < 0)
1.10      db         27:                return (gotoeop(f, -n));
1.1       deraadt    28:
1.3       millert    29:        while (n-- > 0) {
1.1       deraadt    30:                /* first scan back until we are in a word */
1.9       avsm       31:                while (backchar(FFRAND, 1) && inword() == 0);
1.2       millert    32:
1.3       millert    33:                /* and go to the B-O-Line */
                     34:                curwp->w_doto = 0;
1.1       deraadt    35:
1.2       millert    36:                /*
                     37:                 * and scan back until we hit a <NL><SP> <NL><TAB> or
                     38:                 * <NL><NL>
                     39:                 */
1.14      kjell      40:                while (lback(curwp->w_dotp) != curbp->b_headp)
1.7       deraadt    41:                        if (llength(lback(curwp->w_dotp)) &&
                     42:                            lgetc(curwp->w_dotp, 0) != ' ' &&
                     43:                            lgetc(curwp->w_dotp, 0) != '.' &&
                     44:                            lgetc(curwp->w_dotp, 0) != '\t')
1.1       deraadt    45:                                curwp->w_dotp = lback(curwp->w_dotp);
                     46:                        else {
1.7       deraadt    47:                                if (llength(lback(curwp->w_dotp)) &&
                     48:                                    lgetc(curwp->w_dotp, 0) == '.') {
1.2       millert    49:                                        curwp->w_dotp = lforw(curwp->w_dotp);
1.14      kjell      50:                                        if (curwp->w_dotp == curbp->b_headp) {
1.2       millert    51:                                                /*
1.10      db         52:                                                 * beyond end of buffer,
1.2       millert    53:                                                 * cleanup time
                     54:                                                 */
1.6       mickey     55:                                                curwp->w_dotp =
1.3       millert    56:                                                    lback(curwp->w_dotp);
1.6       mickey     57:                                                curwp->w_doto =
1.3       millert    58:                                                    llength(curwp->w_dotp);
1.2       millert    59:                                        }
                     60:                                }
                     61:                                break;
                     62:                        }
1.1       deraadt    63:        }
1.3       millert    64:        /* force screen update */
1.19      kjell      65:        curwp->w_rflag |= WFMOVE;
1.10      db         66:        return (TRUE);
1.1       deraadt    67: }
                     68:
                     69: /*
1.10      db         70:  * Move to end of paragraph.  Go forward to the end of the current paragraph
1.6       mickey     71:  * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> combination to
1.10      db         72:  * delimit the beginning of a paragraph.
1.1       deraadt    73:  */
1.2       millert    74: /* ARGSUSED */
1.3       millert    75: int
1.8       cloder     76: gotoeop(int f, int n)
1.1       deraadt    77: {
1.3       millert    78:        /* the other way... */
                     79:        if (n < 0)
1.10      db         80:                return (gotobop(f, -n));
1.1       deraadt    81:
1.3       millert    82:        /* for each one asked for */
                     83:        while (n-- > 0) {
1.1       deraadt    84:                /* Find the first word on/after the current line */
                     85:                curwp->w_doto = 0;
1.9       avsm       86:                while (forwchar(FFRAND, 1) && inword() == 0);
1.3       millert    87:
1.1       deraadt    88:                curwp->w_doto = 0;
                     89:                curwp->w_dotp = lforw(curwp->w_dotp);
1.3       millert    90:
1.1       deraadt    91:                /* and scan forword until we hit a <NL><SP> or ... */
1.14      kjell      92:                while (curwp->w_dotp != curbp->b_headp) {
1.7       deraadt    93:                        if (llength(curwp->w_dotp) &&
                     94:                            lgetc(curwp->w_dotp, 0) != ' ' &&
                     95:                            lgetc(curwp->w_dotp, 0) != '.' &&
                     96:                            lgetc(curwp->w_dotp, 0) != '\t')
1.1       deraadt    97:                                curwp->w_dotp = lforw(curwp->w_dotp);
                     98:                        else
                     99:                                break;
                    100:                }
1.14      kjell     101:                if (curwp->w_dotp == curbp->b_headp) {
1.10      db        102:                        /* beyond end of buffer, cleanup time */
1.1       deraadt   103:                        curwp->w_dotp = lback(curwp->w_dotp);
                    104:                        curwp->w_doto = llength(curwp->w_dotp);
1.2       millert   105:                        break;
1.1       deraadt   106:                }
                    107:        }
1.3       millert   108:        /* force screen update */
1.19      kjell     109:        curwp->w_rflag |= WFMOVE;
1.10      db        110:        return (TRUE);
1.1       deraadt   111: }
                    112:
                    113: /*
1.6       mickey    114:  * Justify a paragraph.  Fill the current paragraph according to the current
1.3       millert   115:  * fill column.
1.1       deraadt   116:  */
1.2       millert   117: /* ARGSUSED */
1.3       millert   118: int
1.8       cloder    119: fillpara(int f, int n)
1.1       deraadt   120: {
1.10      db        121:        int      c;             /* current char during scan             */
1.3       millert   122:        int      wordlen;       /* length of current word               */
                    123:        int      clength;       /* position on line during fill         */
                    124:        int      i;             /* index during word copy               */
                    125:        int      eopflag;       /* Are we at the End-Of-Paragraph?      */
                    126:        int      firstflag;     /* first word? (needs no space)         */
                    127:        int      newlength;     /* tentative new line length            */
                    128:        int      eolflag;       /* was at end of line                   */
1.12      kjell     129:        int      retval;        /* return value                         */
1.13      deraadt   130:        struct line     *eopline;       /* pointer to line just past EOP        */
1.3       millert   131:        char     wbuf[MAXWORD]; /* buffer for current word              */
1.1       deraadt   132:
1.17      kjell     133:        undo_boundary_enable(FFRAND, 0);
1.12      kjell     134:
1.1       deraadt   135:        /* record the pointer to the line just past the EOP */
1.5       art       136:        (void)gotoeop(FFRAND, 1);
1.2       millert   137:        if (curwp->w_doto != 0) {
1.1       deraadt   138:                /* paragraph ends at end of buffer */
1.5       art       139:                (void)lnewline();
1.1       deraadt   140:                eopline = lforw(curwp->w_dotp);
1.2       millert   141:        } else
                    142:                eopline = curwp->w_dotp;
1.1       deraadt   143:
                    144:        /* and back top the begining of the paragraph */
1.5       art       145:        (void)gotobop(FFRAND, 1);
1.1       deraadt   146:
                    147:        /* initialize various info */
1.9       avsm      148:        while (inword() == 0 && forwchar(FFRAND, 1));
1.3       millert   149:
1.1       deraadt   150:        clength = curwp->w_doto;
                    151:        wordlen = 0;
                    152:
                    153:        /* scan through lines, filling words */
                    154:        firstflag = TRUE;
                    155:        eopflag = FALSE;
                    156:        while (!eopflag) {
1.3       millert   157:
1.1       deraadt   158:                /* get the next character in the paragraph */
1.3       millert   159:                if ((eolflag = (curwp->w_doto == llength(curwp->w_dotp)))) {
1.1       deraadt   160:                        c = ' ';
                    161:                        if (lforw(curwp->w_dotp) == eopline)
                    162:                                eopflag = TRUE;
                    163:                } else
                    164:                        c = lgetc(curwp->w_dotp, curwp->w_doto);
                    165:
                    166:                /* and then delete it */
1.12      kjell     167:                if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag) {
                    168:                        retval = FALSE;
                    169:                        goto cleanup;
                    170:                }
1.1       deraadt   171:
                    172:                /* if not a separator, just add it in */
                    173:                if (c != ' ' && c != '\t') {
                    174:                        if (wordlen < MAXWORD - 1)
                    175:                                wbuf[wordlen++] = c;
                    176:                        else {
1.2       millert   177:                                /*
1.21      matthew   178:                                 * You lose chars beyond MAXWORD if the word
                    179:                                 * is too long. I'm too lazy to fix it now; it
1.2       millert   180:                                 * just silently truncated the word before,
                    181:                                 * so I get to feel smug.
1.1       deraadt   182:                                 */
                    183:                                ewprintf("Word too long!");
                    184:                        }
                    185:                } else if (wordlen) {
1.3       millert   186:
1.10      db        187:                        /* calculate tentative new length with word added */
1.1       deraadt   188:                        newlength = clength + 1 + wordlen;
1.3       millert   189:
1.2       millert   190:                        /*
                    191:                         * if at end of line or at doublespace and previous
1.1       deraadt   192:                         * character was one of '.','?','!' doublespace here.
1.20      lum       193:                         * behave the same way if a ')' is preceded by a
                    194:                         * [.?!] and followed by a doublespace.
1.1       deraadt   195:                         */
1.6       mickey    196:                        if ((eolflag ||
                    197:                            curwp->w_doto == llength(curwp->w_dotp) ||
1.3       millert   198:                            (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' '
1.20      lum       199:                            || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) ||
1.22    ! lum       200:                            (wbuf[wordlen - 1] == ')' && wordlen >= 2 &&
1.20      lum       201:                            ISEOSP(wbuf[wordlen - 2]))) &&
1.3       millert   202:                            wordlen < MAXWORD - 1)
1.1       deraadt   203:                                wbuf[wordlen++] = ' ';
1.3       millert   204:
1.1       deraadt   205:                        /* at a word break with a word waiting */
                    206:                        if (newlength <= fillcol) {
                    207:                                /* add word to current line */
                    208:                                if (!firstflag) {
1.5       art       209:                                        (void)linsert(1, ' ');
1.1       deraadt   210:                                        ++clength;
                    211:                                }
                    212:                                firstflag = FALSE;
                    213:                        } else {
1.2       millert   214:                                if (curwp->w_doto > 0 &&
                    215:                                    lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') {
1.1       deraadt   216:                                        curwp->w_doto -= 1;
1.5       art       217:                                        (void)ldelete((RSIZE) 1, KNONE);
1.1       deraadt   218:                                }
                    219:                                /* start a new line */
1.5       art       220:                                (void)lnewline();
1.1       deraadt   221:                                clength = 0;
                    222:                        }
                    223:
                    224:                        /* and add the word in in either case */
1.2       millert   225:                        for (i = 0; i < wordlen; i++) {
1.5       art       226:                                (void)linsert(1, wbuf[i]);
1.1       deraadt   227:                                ++clength;
                    228:                        }
                    229:                        wordlen = 0;
                    230:                }
                    231:        }
                    232:        /* and add a last newline for the end of our new paragraph */
1.5       art       233:        (void)lnewline();
1.3       millert   234:
1.2       millert   235:        /*
1.10      db        236:         * We really should wind up where we started, (which is hard to keep
1.1       deraadt   237:         * track of) but I think the end of the last line is better than the
1.10      db        238:         * beginning of the blank line.
1.2       millert   239:         */
1.5       art       240:        (void)backchar(FFRAND, 1);
1.12      kjell     241:        retval = TRUE;
                    242: cleanup:
1.17      kjell     243:        undo_boundary_enable(FFRAND, 1);
1.12      kjell     244:        return (retval);
1.1       deraadt   245: }
                    246:
1.6       mickey    247: /*
1.3       millert   248:  * Delete a paragraph.  Delete n paragraphs starting with the current one.
                    249:  */
1.2       millert   250: /* ARGSUSED */
1.3       millert   251: int
1.8       cloder    252: killpara(int f, int n)
1.1       deraadt   253: {
1.3       millert   254:        int     status;         /* returned status of functions */
1.1       deraadt   255:
1.3       millert   256:        /* for each paragraph to delete */
                    257:        while (n--) {
1.1       deraadt   258:
1.10      db        259:                /* mark out the end and beginning of the para to delete */
1.5       art       260:                (void)gotoeop(FFRAND, 1);
1.1       deraadt   261:
                    262:                /* set the mark here */
                    263:                curwp->w_markp = curwp->w_dotp;
                    264:                curwp->w_marko = curwp->w_doto;
                    265:
1.10      db        266:                /* go to the beginning of the paragraph */
1.5       art       267:                (void)gotobop(FFRAND, 1);
1.3       millert   268:
                    269:                /* force us to the beginning of line */
                    270:                curwp->w_doto = 0;
1.1       deraadt   271:
                    272:                /* and delete it */
                    273:                if ((status = killregion(FFRAND, 1)) != TRUE)
1.10      db        274:                        return (status);
1.1       deraadt   275:
                    276:                /* and clean up the 2 extra lines */
1.5       art       277:                (void)ldelete((RSIZE) 1, KFORW);
1.1       deraadt   278:        }
1.10      db        279:        return (TRUE);
1.1       deraadt   280: }
                    281:
                    282: /*
1.3       millert   283:  * Insert char with work wrap.  Check to see if we're past fillcol, and if so,
                    284:  * justify this line.  As a last step, justify the line.
1.1       deraadt   285:  */
1.2       millert   286: /* ARGSUSED */
1.3       millert   287: int
1.8       cloder    288: fillword(int f, int n)
1.1       deraadt   289: {
1.3       millert   290:        char    c;
                    291:        int     col, i, nce;
1.1       deraadt   292:
                    293:        for (i = col = 0; col <= fillcol; ++i, ++col) {
1.2       millert   294:                if (i == curwp->w_doto)
                    295:                        return selfinsert(f, n);
1.1       deraadt   296:                c = lgetc(curwp->w_dotp, i);
                    297:                if (c == '\t'
1.3       millert   298: #ifdef NOTAB
1.2       millert   299:                    && !(curbp->b_flag & BFNOTAB)
1.1       deraadt   300: #endif
1.2       millert   301:                        )
                    302:                        col |= 0x07;
                    303:                else if (ISCTRL(c) != FALSE)
                    304:                        ++col;
1.1       deraadt   305:        }
                    306:        if (curwp->w_doto != llength(curwp->w_dotp)) {
1.5       art       307:                (void)selfinsert(f, n);
1.1       deraadt   308:                nce = llength(curwp->w_dotp) - curwp->w_doto;
1.2       millert   309:        } else
                    310:                nce = 0;
1.1       deraadt   311:        curwp->w_doto = i;
                    312:
                    313:        if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
                    314:                do {
1.5       art       315:                        (void)backchar(FFRAND, 1);
1.7       deraadt   316:                } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
                    317:                    c != '\t' && curwp->w_doto > 0);
1.1       deraadt   318:
                    319:        if (curwp->w_doto == 0)
                    320:                do {
1.5       art       321:                        (void)forwchar(FFRAND, 1);
1.7       deraadt   322:                } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
                    323:                    c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
1.1       deraadt   324:
1.5       art       325:        (void)delwhite(FFRAND, 1);
                    326:        (void)lnewline();
1.1       deraadt   327:        i = llength(curwp->w_dotp) - nce;
1.2       millert   328:        curwp->w_doto = i > 0 ? i : 0;
1.19      kjell     329:        curwp->w_rflag |= WFMOVE;
1.2       millert   330:        if (nce == 0 && curwp->w_doto != 0)
1.10      db        331:                return (fillword(f, n));
                    332:        return (TRUE);
1.1       deraadt   333: }
                    334:
1.3       millert   335: /*
                    336:  * Set fill column to n for justify.
                    337:  */
                    338: int
1.8       cloder    339: setfillcol(int f, int n)
1.2       millert   340: {
1.16      kjell     341:        char buf[32], *rep;
                    342:        const char *es;
1.18      kjell     343:        int nfill;
1.16      kjell     344:
                    345:        if ((f & FFARG) != 0) {
                    346:                fillcol = n;
                    347:        } else {
                    348:                if ((rep = eread("Set fill-column: ", buf, sizeof(buf),
                    349:                    EFNEW | EFCR)) == NULL)
                    350:                        return (ABORT);
                    351:                else if (rep[0] == '\0')
                    352:                        return (FALSE);
1.18      kjell     353:                nfill = strtonum(rep, 0, INT_MAX, &es);
                    354:                if (es != NULL) {
                    355:                        ewprintf("Invalid fill column: %s", rep);
1.16      kjell     356:                        return (FALSE);
1.18      kjell     357:                }
                    358:                fillcol = nfill;
1.16      kjell     359:                ewprintf("Fill column set to %d", fillcol);
                    360:        }
1.10      db        361:        return (TRUE);
1.1       deraadt   362: }