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