Annotation of src/usr.bin/mg/paragraph.c, Revision 1.36
1.36 ! bcallah 1: /* $OpenBSD: paragraph.c,v 1.35 2014/11/16 04:16:41 guenther 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.36 ! bcallah 10: #include <sys/queue.h>
1.24 lum 11: #include <ctype.h>
1.35 guenther 12: #include <limits.h>
1.36 ! bcallah 13: #include <signal.h>
! 14: #include <stdio.h>
! 15: #include <stdlib.h>
1.24 lum 16:
1.1 deraadt 17: #include "def.h"
18:
1.3 millert 19: static int fillcol = 70;
20:
1.1 deraadt 21: #define MAXWORD 256
22:
23: /*
1.27 lum 24: * Move to start of paragraph.
25: * Move backwards by line, checking from the 1st character forwards for the
26: * existence a non-space. If a non-space character is found, move to the
27: * preceding line. Keep doing this until a line with only spaces is found or
28: * the start of buffer.
1.1 deraadt 29: */
1.2 millert 30: /* ARGSUSED */
1.3 millert 31: int
1.8 cloder 32: gotobop(int f, int n)
1.1 deraadt 33: {
1.26 lum 34: int col, nospace;
1.24 lum 35:
1.3 millert 36: /* the other way... */
37: if (n < 0)
1.10 db 38: return (gotoeop(f, -n));
1.1 deraadt 39:
1.3 millert 40: while (n-- > 0) {
1.31 florian 41: nospace = 0;
1.24 lum 42: while (lback(curwp->w_dotp) != curbp->b_headp) {
43: curwp->w_doto = 0;
44: col = 0;
45:
46: while (col < llength(curwp->w_dotp) &&
47: (isspace(lgetc(curwp->w_dotp, col))))
48: col++;
49:
50: if (col >= llength(curwp->w_dotp)) {
51: if (nospace)
52: break;
53: } else
54: nospace = 1;
1.32 lum 55:
56: curwp->w_dotline--;
57: curwp->w_dotp = lback(curwp->w_dotp);
1.24 lum 58: }
1.1 deraadt 59: }
1.3 millert 60: /* force screen update */
1.19 kjell 61: curwp->w_rflag |= WFMOVE;
1.10 db 62: return (TRUE);
1.1 deraadt 63: }
64:
65: /*
1.27 lum 66: * Move to end of paragraph.
67: * See comments for gotobop(). Same, but moving forwards.
1.1 deraadt 68: */
1.2 millert 69: /* ARGSUSED */
1.3 millert 70: int
1.8 cloder 71: gotoeop(int f, int n)
1.1 deraadt 72: {
1.26 lum 73: int col, nospace;
1.25 lum 74:
1.3 millert 75: /* the other way... */
76: if (n < 0)
1.10 db 77: return (gotobop(f, -n));
1.1 deraadt 78:
1.3 millert 79: /* for each one asked for */
80: while (n-- > 0) {
1.31 florian 81: nospace = 0;
1.25 lum 82: while (lforw(curwp->w_dotp) != curbp->b_headp) {
83: col = 0;
84: curwp->w_doto = 0;
85:
86: while (col < llength(curwp->w_dotp) &&
87: (isspace(lgetc(curwp->w_dotp, col))))
88: col++;
89:
90: if (col >= llength(curwp->w_dotp)) {
91: if (nospace)
92: break;
1.23 lum 93: } else
1.25 lum 94: nospace = 1;
95:
96: curwp->w_dotp = lforw(curwp->w_dotp);
97: curwp->w_dotline++;
1.34 lum 98:
99: /* do not continue after end of buffer */
100: if (lforw(curwp->w_dotp) == curbp->b_headp) {
101: gotoeol(FFRAND, 1);
102: curwp->w_rflag |= WFMOVE;
103: return (FALSE);
104: }
1.1 deraadt 105: }
106: }
1.33 lum 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.34 lum 254: int status, end = FALSE; /* 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.34 lum 260: if (!gotoeop(FFRAND, 1))
261: end = TRUE;
1.1 deraadt 262:
263: /* set the mark here */
264: curwp->w_markp = curwp->w_dotp;
265: curwp->w_marko = curwp->w_doto;
266:
1.10 db 267: /* go to the beginning of the paragraph */
1.5 art 268: (void)gotobop(FFRAND, 1);
1.3 millert 269:
270: /* force us to the beginning of line */
271: curwp->w_doto = 0;
1.1 deraadt 272:
273: /* and delete it */
274: if ((status = killregion(FFRAND, 1)) != TRUE)
1.10 db 275: return (status);
1.34 lum 276:
277: if (end)
278: return (TRUE);
1.1 deraadt 279: }
1.10 db 280: return (TRUE);
1.1 deraadt 281: }
282:
283: /*
1.3 millert 284: * Insert char with work wrap. Check to see if we're past fillcol, and if so,
285: * justify this line. As a last step, justify the line.
1.1 deraadt 286: */
1.2 millert 287: /* ARGSUSED */
1.3 millert 288: int
1.8 cloder 289: fillword(int f, int n)
1.1 deraadt 290: {
1.3 millert 291: char c;
292: int col, i, nce;
1.1 deraadt 293:
294: for (i = col = 0; col <= fillcol; ++i, ++col) {
1.2 millert 295: if (i == curwp->w_doto)
296: return selfinsert(f, n);
1.1 deraadt 297: c = lgetc(curwp->w_dotp, i);
298: if (c == '\t'
1.3 millert 299: #ifdef NOTAB
1.2 millert 300: && !(curbp->b_flag & BFNOTAB)
1.1 deraadt 301: #endif
1.2 millert 302: )
303: col |= 0x07;
304: else if (ISCTRL(c) != FALSE)
305: ++col;
1.1 deraadt 306: }
307: if (curwp->w_doto != llength(curwp->w_dotp)) {
1.5 art 308: (void)selfinsert(f, n);
1.1 deraadt 309: nce = llength(curwp->w_dotp) - curwp->w_doto;
1.2 millert 310: } else
311: nce = 0;
1.1 deraadt 312: curwp->w_doto = i;
313:
314: if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
315: do {
1.5 art 316: (void)backchar(FFRAND, 1);
1.7 deraadt 317: } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
318: c != '\t' && curwp->w_doto > 0);
1.1 deraadt 319:
320: if (curwp->w_doto == 0)
321: do {
1.5 art 322: (void)forwchar(FFRAND, 1);
1.7 deraadt 323: } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
324: c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
1.1 deraadt 325:
1.5 art 326: (void)delwhite(FFRAND, 1);
327: (void)lnewline();
1.1 deraadt 328: i = llength(curwp->w_dotp) - nce;
1.2 millert 329: curwp->w_doto = i > 0 ? i : 0;
1.19 kjell 330: curwp->w_rflag |= WFMOVE;
1.2 millert 331: if (nce == 0 && curwp->w_doto != 0)
1.10 db 332: return (fillword(f, n));
333: return (TRUE);
1.1 deraadt 334: }
335:
1.3 millert 336: /*
337: * Set fill column to n for justify.
338: */
339: int
1.8 cloder 340: setfillcol(int f, int n)
1.2 millert 341: {
1.16 kjell 342: char buf[32], *rep;
343: const char *es;
1.18 kjell 344: int nfill;
1.16 kjell 345:
346: if ((f & FFARG) != 0) {
347: fillcol = n;
348: } else {
349: if ((rep = eread("Set fill-column: ", buf, sizeof(buf),
350: EFNEW | EFCR)) == NULL)
351: return (ABORT);
352: else if (rep[0] == '\0')
353: return (FALSE);
1.18 kjell 354: nfill = strtonum(rep, 0, INT_MAX, &es);
355: if (es != NULL) {
1.30 lum 356: dobeep();
1.18 kjell 357: ewprintf("Invalid fill column: %s", rep);
1.16 kjell 358: return (FALSE);
1.18 kjell 359: }
360: fillcol = nfill;
1.16 kjell 361: ewprintf("Fill column set to %d", fillcol);
362: }
1.10 db 363: return (TRUE);
1.1 deraadt 364: }