]> pd.if.org Git - pd_readline/blob - mg/paragraph.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / paragraph.c
1 /*      $OpenBSD: paragraph.c,v 1.22 2011/11/29 05:59:54 lum Exp $      */
2
3 /* This file is in the public domain. */
4
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  */
9
10 #include "def.h"
11
12 static int      fillcol = 70;
13
14 #define MAXWORD 256
15
16 /*
17  * Move to start of paragraph.  Go back to the beginning of the current
18  * paragraph here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
19  * combination to delimit the beginning of a paragraph.
20  */
21 /* ARGSUSED */
22 int
23 gotobop(int f, int n)
24 {
25         /* the other way... */
26         if (n < 0)
27                 return (gotoeop(f, -n));
28
29         while (n-- > 0) {
30                 /* first scan back until we are in a word */
31                 while (backchar(FFRAND, 1) && inword() == 0);
32
33                 /* and go to the B-O-Line */
34                 curwp->w_doto = 0;
35
36                 /*
37                  * and scan back until we hit a <NL><SP> <NL><TAB> or
38                  * <NL><NL>
39                  */
40                 while (lback(curwp->w_dotp) != curbp->b_headp)
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')
45                                 curwp->w_dotp = lback(curwp->w_dotp);
46                         else {
47                                 if (llength(lback(curwp->w_dotp)) &&
48                                     lgetc(curwp->w_dotp, 0) == '.') {
49                                         curwp->w_dotp = lforw(curwp->w_dotp);
50                                         if (curwp->w_dotp == curbp->b_headp) {
51                                                 /*
52                                                  * beyond end of buffer,
53                                                  * cleanup time
54                                                  */
55                                                 curwp->w_dotp =
56                                                     lback(curwp->w_dotp);
57                                                 curwp->w_doto =
58                                                     llength(curwp->w_dotp);
59                                         }
60                                 }
61                                 break;
62                         }
63         }
64         /* force screen update */
65         curwp->w_rflag |= WFMOVE;
66         return (TRUE);
67 }
68
69 /*
70  * Move to end of paragraph.  Go forward to the end of the current paragraph
71  * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> combination to
72  * delimit the beginning of a paragraph.
73  */
74 /* ARGSUSED */
75 int
76 gotoeop(int f, int 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() == 0);
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_headp) {
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_headp) {
102                         /* beyond 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_rflag |= 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(int f, int n)
120 {
121         int      c;             /* current char during scan             */
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                   */
129         int      retval;        /* return value                         */
130         struct line     *eopline;       /* pointer to line just past EOP        */
131         char     wbuf[MAXWORD]; /* buffer for current word              */
132
133         undo_boundary_enable(FFRAND, 0);
134
135         /* record the pointer to the line just past the EOP */
136         (void)gotoeop(FFRAND, 1);
137         if (curwp->w_doto != 0) {
138                 /* paragraph ends at end of buffer */
139                 (void)lnewline();
140                 eopline = lforw(curwp->w_dotp);
141         } else
142                 eopline = curwp->w_dotp;
143
144         /* and back top the begining of the paragraph */
145         (void)gotobop(FFRAND, 1);
146
147         /* initialize various info */
148         while (inword() == 0 && forwchar(FFRAND, 1));
149
150         clength = curwp->w_doto;
151         wordlen = 0;
152
153         /* scan through lines, filling words */
154         firstflag = TRUE;
155         eopflag = FALSE;
156         while (!eopflag) {
157
158                 /* get the next character in the paragraph */
159                 if ((eolflag = (curwp->w_doto == llength(curwp->w_dotp)))) {
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 */
167                 if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag) {
168                         retval = FALSE;
169                         goto cleanup;
170                 }
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 {
177                                 /*
178                                  * You lose chars beyond MAXWORD if the word
179                                  * is too long. I'm too lazy to fix it now; it
180                                  * just silently truncated the word before,
181                                  * so I get to feel smug.
182                                  */
183                                 ewprintf("Word too long!");
184                         }
185                 } else if (wordlen) {
186
187                         /* calculate tentative new length with word added */
188                         newlength = clength + 1 + wordlen;
189
190                         /*
191                          * if at end of line or at doublespace and previous
192                          * character was one of '.','?','!' doublespace here.
193                          * behave the same way if a ')' is preceded by a
194                          * [.?!] and followed by a doublespace.
195                          */
196                         if ((eolflag ||
197                             curwp->w_doto == llength(curwp->w_dotp) ||
198                             (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' '
199                             || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) ||
200                             (wbuf[wordlen - 1] == ')' && wordlen >= 2 &&
201                             ISEOSP(wbuf[wordlen - 2]))) &&
202                             wordlen < MAXWORD - 1)
203                                 wbuf[wordlen++] = ' ';
204
205                         /* at a word break with a word waiting */
206                         if (newlength <= fillcol) {
207                                 /* add word to current line */
208                                 if (!firstflag) {
209                                         (void)linsert(1, ' ');
210                                         ++clength;
211                                 }
212                                 firstflag = FALSE;
213                         } else {
214                                 if (curwp->w_doto > 0 &&
215                                     lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') {
216                                         curwp->w_doto -= 1;
217                                         (void)ldelete((RSIZE) 1, KNONE);
218                                 }
219                                 /* start a new line */
220                                 (void)lnewline();
221                                 clength = 0;
222                         }
223
224                         /* and add the word in in either case */
225                         for (i = 0; i < wordlen; i++) {
226                                 (void)linsert(1, wbuf[i]);
227                                 ++clength;
228                         }
229                         wordlen = 0;
230                 }
231         }
232         /* and add a last newline for the end of our new paragraph */
233         (void)lnewline();
234
235         /*
236          * We really should wind up where we started, (which is hard to keep
237          * track of) but I think the end of the last line is better than the
238          * beginning of the blank line.
239          */
240         (void)backchar(FFRAND, 1);
241         retval = TRUE;
242 cleanup:
243         undo_boundary_enable(FFRAND, 1);
244         return (retval);
245 }
246
247 /*
248  * Delete a paragraph.  Delete n paragraphs starting with the current one.
249  */
250 /* ARGSUSED */
251 int
252 killpara(int f, int n)
253 {
254         int     status;         /* returned status of functions */
255
256         /* for each paragraph to delete */
257         while (n--) {
258
259                 /* mark out the end and beginning of the para to delete */
260                 (void)gotoeop(FFRAND, 1);
261
262                 /* set the mark here */
263                 curwp->w_markp = curwp->w_dotp;
264                 curwp->w_marko = curwp->w_doto;
265
266                 /* go to the beginning of the paragraph */
267                 (void)gotobop(FFRAND, 1);
268
269                 /* force us to the beginning of line */
270                 curwp->w_doto = 0;
271
272                 /* and delete it */
273                 if ((status = killregion(FFRAND, 1)) != TRUE)
274                         return (status);
275
276                 /* and clean up the 2 extra lines */
277                 (void)ldelete((RSIZE) 1, KFORW);
278         }
279         return (TRUE);
280 }
281
282 /*
283  * Insert char with work wrap.  Check to see if we're past fillcol, and if so,
284  * justify this line.  As a last step, justify the line.
285  */
286 /* ARGSUSED */
287 int
288 fillword(int f, int n)
289 {
290         char    c;
291         int     col, i, nce;
292
293         for (i = col = 0; col <= fillcol; ++i, ++col) {
294                 if (i == curwp->w_doto)
295                         return selfinsert(f, n);
296                 c = lgetc(curwp->w_dotp, i);
297                 if (c == '\t'
298 #ifdef NOTAB
299                     && !(curbp->b_flag & BFNOTAB)
300 #endif
301                         )
302                         col |= 0x07;
303                 else if (ISCTRL(c) != FALSE)
304                         ++col;
305         }
306         if (curwp->w_doto != llength(curwp->w_dotp)) {
307                 (void)selfinsert(f, n);
308                 nce = llength(curwp->w_dotp) - curwp->w_doto;
309         } else
310                 nce = 0;
311         curwp->w_doto = i;
312
313         if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
314                 do {
315                         (void)backchar(FFRAND, 1);
316                 } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
317                     c != '\t' && curwp->w_doto > 0);
318
319         if (curwp->w_doto == 0)
320                 do {
321                         (void)forwchar(FFRAND, 1);
322                 } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
323                     c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
324
325         (void)delwhite(FFRAND, 1);
326         (void)lnewline();
327         i = llength(curwp->w_dotp) - nce;
328         curwp->w_doto = i > 0 ? i : 0;
329         curwp->w_rflag |= WFMOVE;
330         if (nce == 0 && curwp->w_doto != 0)
331                 return (fillword(f, n));
332         return (TRUE);
333 }
334
335 /*
336  * Set fill column to n for justify.
337  */
338 int
339 setfillcol(int f, int n)
340 {
341         char buf[32], *rep;
342         const char *es;
343         int nfill;
344
345         if ((f & FFARG) != 0) {
346                 fillcol = n;
347         } else {
348                 if ((rep = eread("Set fill-column: ", buf, sizeof(buf),
349                     EFNEW | EFCR)) == NULL)
350                         return (ABORT);
351                 else if (rep[0] == '\0')
352                         return (FALSE);
353                 nfill = strtonum(rep, 0, INT_MAX, &es);
354                 if (es != NULL) {
355                         ewprintf("Invalid fill column: %s", rep);
356                         return (FALSE);
357                 }
358                 fillcol = nfill;
359                 ewprintf("Fill column set to %d", fillcol);
360         }
361         return (TRUE);
362 }