1 /* $OpenBSD: paragraph.c,v 1.6 2001/05/24 03:05:25 mickey Exp $ */ 2 3 /* 4 * Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6 5 * and GNU-ified by mwm@ucbvax. Several bug fixes by blarson@usc-oberon. 6 */ 7 8 #include "def.h" 9 10 static int fillcol = 70; 11 12 #define MAXWORD 256 13 14 /* 15 * Move to start of paragraph. Go back to the begining of the current 16 * paragraph here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> 17 * combination to delimit the begining of a paragraph. 18 */ 19 /* ARGSUSED */ 20 int 21 gotobop(f, n) 22 int f, n; 23 { 24 /* the other way... */ 25 if (n < 0) 26 return gotoeop(f, -n); 27 28 while (n-- > 0) { 29 /* first scan back until we are in a word */ 30 while (backchar(FFRAND, 1) && inword() == NULL); 31 32 /* and go to the B-O-Line */ 33 curwp->w_doto = 0; 34 35 /* 36 * and scan back until we hit a <NL><SP> <NL><TAB> or 37 * <NL><NL> 38 */ 39 while (lback(curwp->w_dotp) != curbp->b_linep) 40 if (llength(lback(curwp->w_dotp)) 41 && lgetc(curwp->w_dotp, 0) != ' ' 42 && lgetc(curwp->w_dotp, 0) != '.' 43 && lgetc(curwp->w_dotp, 0) != '\t') 44 curwp->w_dotp = lback(curwp->w_dotp); 45 else { 46 if (llength(lback(curwp->w_dotp)) 47 && lgetc(curwp->w_dotp, 0) == '.') { 48 curwp->w_dotp = lforw(curwp->w_dotp); 49 if (curwp->w_dotp == curbp->b_linep) { 50 /* 51 * beond end of buffer, 52 * cleanup time 53 */ 54 curwp->w_dotp = 55 lback(curwp->w_dotp); 56 curwp->w_doto = 57 llength(curwp->w_dotp); 58 } 59 } 60 break; 61 } 62 } 63 /* force screen update */ 64 curwp->w_flag |= WFMOVE; 65 return TRUE; 66 } 67 68 /* 69 * Move to end of paragraph. Go forword to the end of the current paragraph 70 * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> combination to 71 * delimit the begining of a paragraph. 72 */ 73 /* ARGSUSED */ 74 int 75 gotoeop(f, n) 76 int f, n; 77 { 78 /* the other way... */ 79 if (n < 0) 80 return gotobop(f, -n); 81 82 /* for each one asked for */ 83 while (n-- > 0) { 84 /* Find the first word on/after the current line */ 85 curwp->w_doto = 0; 86 while (forwchar(FFRAND, 1) && inword() == NULL); 87 88 curwp->w_doto = 0; 89 curwp->w_dotp = lforw(curwp->w_dotp); 90 91 /* and scan forword until we hit a <NL><SP> or ... */ 92 while (curwp->w_dotp != curbp->b_linep) { 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') 97 curwp->w_dotp = lforw(curwp->w_dotp); 98 else 99 break; 100 } 101 if (curwp->w_dotp == curbp->b_linep) { 102 /* beond end of buffer, cleanup time */ 103 curwp->w_dotp = lback(curwp->w_dotp); 104 curwp->w_doto = llength(curwp->w_dotp); 105 break; 106 } 107 } 108 /* force screen update */ 109 curwp->w_flag |= WFMOVE; 110 return TRUE; 111 } 112 113 /* 114 * Justify a paragraph. Fill the current paragraph according to the current 115 * fill column. 116 */ 117 /* ARGSUSED */ 118 int 119 fillpara(f, n) 120 int f, n; 121 { 122 int c; /* current char durring scan */ 123 int wordlen; /* length of current word */ 124 int clength; /* position on line during fill */ 125 int i; /* index during word copy */ 126 int eopflag; /* Are we at the End-Of-Paragraph? */ 127 int firstflag; /* first word? (needs no space) */ 128 int newlength; /* tentative new line length */ 129 int eolflag; /* was at end of line */ 130 LINE *eopline; /* pointer to line just past EOP */ 131 char wbuf[MAXWORD]; /* buffer for current word */ 132 133 /* record the pointer to the line just past the EOP */ 134 (void)gotoeop(FFRAND, 1); 135 if (curwp->w_doto != 0) { 136 /* paragraph ends at end of buffer */ 137 (void)lnewline(); 138 eopline = lforw(curwp->w_dotp); 139 } else 140 eopline = curwp->w_dotp; 141 142 /* and back top the begining of the paragraph */ 143 (void)gotobop(FFRAND, 1); 144 145 /* initialize various info */ 146 while (inword() == NULL && forwchar(FFRAND, 1)); 147 148 clength = curwp->w_doto; 149 wordlen = 0; 150 151 /* scan through lines, filling words */ 152 firstflag = TRUE; 153 eopflag = FALSE; 154 while (!eopflag) { 155 156 /* get the next character in the paragraph */ 157 if ((eolflag = (curwp->w_doto == llength(curwp->w_dotp)))) { 158 c = ' '; 159 if (lforw(curwp->w_dotp) == eopline) 160 eopflag = TRUE; 161 } else 162 c = lgetc(curwp->w_dotp, curwp->w_doto); 163 164 /* and then delete it */ 165 if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag) 166 return FALSE; 167 168 /* if not a separator, just add it in */ 169 if (c != ' ' && c != '\t') { 170 if (wordlen < MAXWORD - 1) 171 wbuf[wordlen++] = c; 172 else { 173 /* 174 * You loose chars beyond MAXWORD if the word 175 * is to long. I'm to lazy to fix it now; it 176 * just silently truncated the word before, 177 * so I get to feel smug. 178 */ 179 ewprintf("Word too long!"); 180 } 181 } else if (wordlen) { 182 183 /* calculate tenatitive new length with word added */ 184 newlength = clength + 1 + wordlen; 185 186 /* 187 * if at end of line or at doublespace and previous 188 * character was one of '.','?','!' doublespace here. 189 */ 190 if ((eolflag || 191 curwp->w_doto == llength(curwp->w_dotp) || 192 (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' 193 || c == '\t') && ISEOSP(wbuf[wordlen - 1]) && 194 wordlen < MAXWORD - 1) 195 wbuf[wordlen++] = ' '; 196 197 /* at a word break with a word waiting */ 198 if (newlength <= fillcol) { 199 /* add word to current line */ 200 if (!firstflag) { 201 (void)linsert(1, ' '); 202 ++clength; 203 } 204 firstflag = FALSE; 205 } else { 206 if (curwp->w_doto > 0 && 207 lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') { 208 curwp->w_doto -= 1; 209 (void)ldelete((RSIZE) 1, KNONE); 210 } 211 /* start a new line */ 212 (void)lnewline(); 213 clength = 0; 214 } 215 216 /* and add the word in in either case */ 217 for (i = 0; i < wordlen; i++) { 218 (void)linsert(1, wbuf[i]); 219 ++clength; 220 } 221 wordlen = 0; 222 } 223 } 224 /* and add a last newline for the end of our new paragraph */ 225 (void)lnewline(); 226 227 /* 228 * we realy should wind up where we started, (which is hard to keep 229 * track of) but I think the end of the last line is better than the 230 * begining of the blank line. 231 */ 232 (void)backchar(FFRAND, 1); 233 return TRUE; 234 } 235 236 /* 237 * Delete a paragraph. Delete n paragraphs starting with the current one. 238 */ 239 /* ARGSUSED */ 240 int 241 killpara(f, n) 242 int f, n; 243 { 244 int status; /* returned status of functions */ 245 246 /* for each paragraph to delete */ 247 while (n--) { 248 249 /* mark out the end and begining of the para to delete */ 250 (void)gotoeop(FFRAND, 1); 251 252 /* set the mark here */ 253 curwp->w_markp = curwp->w_dotp; 254 curwp->w_marko = curwp->w_doto; 255 256 /* go to the begining of the paragraph */ 257 (void)gotobop(FFRAND, 1); 258 259 /* force us to the beginning of line */ 260 curwp->w_doto = 0; 261 262 /* and delete it */ 263 if ((status = killregion(FFRAND, 1)) != TRUE) 264 return status; 265 266 /* and clean up the 2 extra lines */ 267 (void)ldelete((RSIZE) 1, KFORW); 268 } 269 return TRUE; 270 } 271 272 /* 273 * Insert char with work wrap. Check to see if we're past fillcol, and if so, 274 * justify this line. As a last step, justify the line. 275 */ 276 /* ARGSUSED */ 277 int 278 fillword(f, n) 279 int f, n; 280 { 281 char c; 282 int col, i, nce; 283 284 for (i = col = 0; col <= fillcol; ++i, ++col) { 285 if (i == curwp->w_doto) 286 return selfinsert(f, n); 287 c = lgetc(curwp->w_dotp, i); 288 if (c == '\t' 289 #ifdef NOTAB 290 && !(curbp->b_flag & BFNOTAB) 291 #endif 292 ) 293 col |= 0x07; 294 else if (ISCTRL(c) != FALSE) 295 ++col; 296 } 297 if (curwp->w_doto != llength(curwp->w_dotp)) { 298 (void)selfinsert(f, n); 299 nce = llength(curwp->w_dotp) - curwp->w_doto; 300 } else 301 nce = 0; 302 curwp->w_doto = i; 303 304 if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t') 305 do { 306 (void)backchar(FFRAND, 1); 307 } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' 308 && c != '\t' && curwp->w_doto > 0); 309 310 if (curwp->w_doto == 0) 311 do { 312 (void)forwchar(FFRAND, 1); 313 } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' 314 && c != '\t' && curwp->w_doto < llength(curwp->w_dotp)); 315 316 (void)delwhite(FFRAND, 1); 317 (void)lnewline(); 318 i = llength(curwp->w_dotp) - nce; 319 curwp->w_doto = i > 0 ? i : 0; 320 curwp->w_flag |= WFMOVE; 321 if (nce == 0 && curwp->w_doto != 0) 322 return fillword(f, n); 323 return TRUE; 324 } 325 326 /* 327 * Set fill column to n for justify. 328 */ 329 int 330 setfillcol(f, n) 331 int f, n; 332 { 333 fillcol = ((f & FFARG) ? n : getcolpos()); 334 ewprintf("Fill column set to %d", fillcol); 335 return TRUE; 336 } 337