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