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