Annotation of src/usr.bin/mg/paragraph.c, Revision 1.19
1.19 ! kjell 1: /* $OpenBSD: paragraph.c,v 1.18 2009/06/02 21:55:25 kjell 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: /*
178: * You loose chars beyond MAXWORD if the word
1.1 deraadt 179: * is to long. I'm to 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.
193: */
1.6 mickey 194: if ((eolflag ||
195: curwp->w_doto == llength(curwp->w_dotp) ||
1.3 millert 196: (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' '
1.6 mickey 197: || c == '\t') && ISEOSP(wbuf[wordlen - 1]) &&
1.3 millert 198: wordlen < MAXWORD - 1)
1.1 deraadt 199: wbuf[wordlen++] = ' ';
1.3 millert 200:
1.1 deraadt 201: /* at a word break with a word waiting */
202: if (newlength <= fillcol) {
203: /* add word to current line */
204: if (!firstflag) {
1.5 art 205: (void)linsert(1, ' ');
1.1 deraadt 206: ++clength;
207: }
208: firstflag = FALSE;
209: } else {
1.2 millert 210: if (curwp->w_doto > 0 &&
211: lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') {
1.1 deraadt 212: curwp->w_doto -= 1;
1.5 art 213: (void)ldelete((RSIZE) 1, KNONE);
1.1 deraadt 214: }
215: /* start a new line */
1.5 art 216: (void)lnewline();
1.1 deraadt 217: clength = 0;
218: }
219:
220: /* and add the word in in either case */
1.2 millert 221: for (i = 0; i < wordlen; i++) {
1.5 art 222: (void)linsert(1, wbuf[i]);
1.1 deraadt 223: ++clength;
224: }
225: wordlen = 0;
226: }
227: }
228: /* and add a last newline for the end of our new paragraph */
1.5 art 229: (void)lnewline();
1.3 millert 230:
1.2 millert 231: /*
1.10 db 232: * We really should wind up where we started, (which is hard to keep
1.1 deraadt 233: * track of) but I think the end of the last line is better than the
1.10 db 234: * beginning of the blank line.
1.2 millert 235: */
1.5 art 236: (void)backchar(FFRAND, 1);
1.12 kjell 237: retval = TRUE;
238: cleanup:
1.17 kjell 239: undo_boundary_enable(FFRAND, 1);
1.12 kjell 240: return (retval);
1.1 deraadt 241: }
242:
1.6 mickey 243: /*
1.3 millert 244: * Delete a paragraph. Delete n paragraphs starting with the current one.
245: */
1.2 millert 246: /* ARGSUSED */
1.3 millert 247: int
1.8 cloder 248: killpara(int f, int n)
1.1 deraadt 249: {
1.3 millert 250: int status; /* returned status of functions */
1.1 deraadt 251:
1.3 millert 252: /* for each paragraph to delete */
253: while (n--) {
1.1 deraadt 254:
1.10 db 255: /* mark out the end and beginning of the para to delete */
1.5 art 256: (void)gotoeop(FFRAND, 1);
1.1 deraadt 257:
258: /* set the mark here */
259: curwp->w_markp = curwp->w_dotp;
260: curwp->w_marko = curwp->w_doto;
261:
1.10 db 262: /* go to the beginning of the paragraph */
1.5 art 263: (void)gotobop(FFRAND, 1);
1.3 millert 264:
265: /* force us to the beginning of line */
266: curwp->w_doto = 0;
1.1 deraadt 267:
268: /* and delete it */
269: if ((status = killregion(FFRAND, 1)) != TRUE)
1.10 db 270: return (status);
1.1 deraadt 271:
272: /* and clean up the 2 extra lines */
1.5 art 273: (void)ldelete((RSIZE) 1, KFORW);
1.1 deraadt 274: }
1.10 db 275: return (TRUE);
1.1 deraadt 276: }
277:
278: /*
1.3 millert 279: * Insert char with work wrap. Check to see if we're past fillcol, and if so,
280: * justify this line. As a last step, justify the line.
1.1 deraadt 281: */
1.2 millert 282: /* ARGSUSED */
1.3 millert 283: int
1.8 cloder 284: fillword(int f, int n)
1.1 deraadt 285: {
1.3 millert 286: char c;
287: int col, i, nce;
1.1 deraadt 288:
289: for (i = col = 0; col <= fillcol; ++i, ++col) {
1.2 millert 290: if (i == curwp->w_doto)
291: return selfinsert(f, n);
1.1 deraadt 292: c = lgetc(curwp->w_dotp, i);
293: if (c == '\t'
1.3 millert 294: #ifdef NOTAB
1.2 millert 295: && !(curbp->b_flag & BFNOTAB)
1.1 deraadt 296: #endif
1.2 millert 297: )
298: col |= 0x07;
299: else if (ISCTRL(c) != FALSE)
300: ++col;
1.1 deraadt 301: }
302: if (curwp->w_doto != llength(curwp->w_dotp)) {
1.5 art 303: (void)selfinsert(f, n);
1.1 deraadt 304: nce = llength(curwp->w_dotp) - curwp->w_doto;
1.2 millert 305: } else
306: nce = 0;
1.1 deraadt 307: curwp->w_doto = i;
308:
309: if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
310: do {
1.5 art 311: (void)backchar(FFRAND, 1);
1.7 deraadt 312: } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
313: c != '\t' && curwp->w_doto > 0);
1.1 deraadt 314:
315: if (curwp->w_doto == 0)
316: do {
1.5 art 317: (void)forwchar(FFRAND, 1);
1.7 deraadt 318: } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
319: c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
1.1 deraadt 320:
1.5 art 321: (void)delwhite(FFRAND, 1);
322: (void)lnewline();
1.1 deraadt 323: i = llength(curwp->w_dotp) - nce;
1.2 millert 324: curwp->w_doto = i > 0 ? i : 0;
1.19 ! kjell 325: curwp->w_rflag |= WFMOVE;
1.2 millert 326: if (nce == 0 && curwp->w_doto != 0)
1.10 db 327: return (fillword(f, n));
328: return (TRUE);
1.1 deraadt 329: }
330:
1.3 millert 331: /*
332: * Set fill column to n for justify.
333: */
334: int
1.8 cloder 335: setfillcol(int f, int n)
1.2 millert 336: {
1.16 kjell 337: char buf[32], *rep;
338: const char *es;
1.18 kjell 339: int nfill;
1.16 kjell 340:
341: if ((f & FFARG) != 0) {
342: fillcol = n;
343: } else {
344: if ((rep = eread("Set fill-column: ", buf, sizeof(buf),
345: EFNEW | EFCR)) == NULL)
346: return (ABORT);
347: else if (rep[0] == '\0')
348: return (FALSE);
1.18 kjell 349: nfill = strtonum(rep, 0, INT_MAX, &es);
350: if (es != NULL) {
351: ewprintf("Invalid fill column: %s", rep);
1.16 kjell 352: return (FALSE);
1.18 kjell 353: }
354: fillcol = nfill;
1.16 kjell 355: ewprintf("Fill column set to %d", fillcol);
356: }
1.10 db 357: return (TRUE);
1.1 deraadt 358: }