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