mtree: no more /lib and /lib/i386.
[minix.git] / commands / elle / eefill.c
blob50d7d28d54ce048a8a150593fc59f3bc3a9f37fd
1 /* ELLE - Copyright 1982, 1985, 1987 by Ken Harrenstien, SRI International
2 * This software is quasi-public; it may be used freely with
3 * like software, but may NOT be sold or made part of licensed
4 * products without permission of the author.
5 */
6 /*
7 * EEFILL Fill Mode functions
8 */
10 #include "elle.h"
12 extern int ev_fcolumn; /* Fill Column variable (defined in EEVINI) */
13 #if FX_SFPREF
14 char *fill_prefix; /* Fill Prefix variable */
15 int fill_plen; /* Length of Fill Prefix (0 = no prefix) */
16 #endif /*FX_SFPREF*/
18 #if FX_FILLMODE
19 int fill_mode = 0; /* TRUE when Auto Fill Mode is on */
20 int *fill_trig; /* Pointer to fill-trigger chbit array */
21 static char *fill_initrig = " \t.,;:)!";
22 #endif /*FX_FILLMODE*/
24 /* Following stuff for testing routines on */
27 1 2 3 4 5 6 7
28 0123456789012345678901234567890123456789012345678901234567890123456789012345
30 Okay... more stuff to hack. Okay. a b c d e f g h i j k l m
31 n o p q r s t u v w x y z dfsd stuff to hack 01234 Okay testing
32 more stuff to hack. Okay... more stuff to hack more stuff to
33 hack. Okay... more stuff to line long stuff to hack. Okay...
34 even more gap and. period. okay, end of stuff.
35 This is another fence.
39 #if FX_SFCOL
40 /* EFUN: "Set Fill Column" */
41 f_sfcol()
42 { register int linel;
43 char temp[20];
45 linel = exp_p ? exp : d_curind();
46 if(linel < 0) linel = 0;
47 say("Fill column = ");
48 dottoa(temp,(chroff)linel);
49 saytoo(temp);
50 ev_fcolumn = linel;
52 #endif /*FX_SFCOL*/
55 #if FX_SFPREF
56 /* EFUN: "Set Fill Prefix" */
57 f_sfpref()
58 { register int i;
59 register char *cp;
61 if((i = cur_dot - e_boldot()) > MAXLINE)
62 { ding("Absurd Fill Prefix");
63 return;
65 if(fill_prefix)
66 { chkfree(fill_prefix);
67 fill_plen = 0;
69 if(i <= 0)
70 { fill_prefix = 0;
71 cp = "";
73 else
74 { fill_prefix = cp = memalloc((SBMO)(i+1));
75 fill_plen = i;
76 e_gobol();
77 do { *cp++ = e_getc(); }
78 while(--i);
79 *cp = 0;
80 cp = fill_prefix;
82 say("Fill Prefix = \"");
83 saytoo(cp);
84 saytoo("\"");
88 /* TSTFILLP(lim) - Check for existence of Fill Prefix at current dot. If
89 * not there, returns 0 without changing dot. If there, returns
90 * 1 and leaves dot immediately after the Fill Prefix.
91 * Lim = # of chars allowed to scan from buffer.
93 tstfillp(lim)
94 int lim;
95 { register int i;
96 register char *cp;
97 chroff savdot;
99 if(!(i = fill_plen) || (i > lim))
100 return(0);
101 savdot = e_dot();
102 cp = fill_prefix;
103 do { if(*cp++ != e_getc())
104 { e_go(savdot);
105 return(0);
107 } while(--i);
108 return(1);
110 #endif /*FX_SFPREF*/
112 #if FX_FILLREG || FX_FILLPARA
114 /* ED_FILL(start, end, flag) - Fill a region.
115 * Flag 0 for full filling; extra whitespace is flushed. First
116 * word is always retained.
117 * 1 for skimpy filling such as Auto-Fill likes.
118 * Extra whitespace is NOT flushed, except at
119 * beginning of a newly created line.
120 * This is not yet implemented however.
121 * Note: updates cur_dot to compensate for changes in buffer, and returns
122 * there when done!
123 * Note: Checks for Fill Prefix when it exists.
125 ed_fill(begloc, endloc, flag)
126 chroff begloc, endloc;
127 int flag;
128 { register int c;
129 register int len, lastc;
130 chroff savloc;
131 int lastbrk;
132 int parlen;
134 parlen = endloc - begloc;
135 if(parlen < 0)
136 { begloc = endloc;
137 parlen = -parlen;
139 e_go(begloc);
140 len = d_curind(); /* Set up current col */
142 #if FX_SFPREF
143 /* If at beg of line, check for fill prefix and skip over it */
144 if((len == 0) && tstfillp(parlen))
145 { parlen -= fill_plen;
146 len = d_curind();
148 #endif /*FX_SFPREF*/
149 lastbrk = 0; /* Put next word on no matter what. */
150 c = 0;
151 for(;;)
153 #if ICONOGRAPHICS
154 if (c != ')' && c != '"') /* allow for two sp after .) or ." */
155 #endif /*ICONOGRAPHICS*/
156 lastc = c;
157 if(--parlen < 0) break;
158 c = e_getc();
159 if(c == EOF)
160 break;
161 #if FX_SFPREF
162 /* If at beg of line, check for fill prefix and flush it */
163 if((c == LF) && tstfillp(parlen))
164 { e_igoff(-(fill_plen+1));
165 e_ovwc(c = SP);
166 e_deln((chroff)fill_plen);
167 parlen -= fill_plen;
168 if(cur_dot >= e_dot())
169 cur_dot -= fill_plen;
171 #endif /*FX_SFPREF*/
172 if(c == TAB || c == LF) /* Replace tabs+eols by sps */
173 { e_backc(); /* Back up 1 */
174 e_ovwc(c = SP);
176 if(c == SP)
177 { if(lastc == SP)
178 { e_rdelc();
179 if(cur_dot > e_dot()) --cur_dot;
180 continue;
182 lastbrk = len;
183 if(lastc == '.' || lastc == '!' || lastc == '?'
184 #if ICONOGRAPHICS
185 || lastc == ':'
186 #endif /*ICONOGRAPHICS*/
188 { if(--parlen < 0) goto done;
189 if((c = e_getc()) == EOF)
190 goto done;
191 len++;
192 if(c != SP)
193 { e_backc();
194 e_putc(c = SP);
195 if(cur_dot >= e_dot()) ++cur_dot;
199 #if ICONOGRAPHICS
200 if (c == BS) /* adjust for backspaces */
201 if ((len -= 2) < 0) len = 0;
202 #endif /*ICONOGRAPHICS*/
203 /* Normal char */
204 if(++len > ev_fcolumn && lastbrk) /* If went too far */
205 { c = lastbrk - len; /* Must put EOL at last SP */
206 e_igoff(c);
207 parlen -= c; /* C is negative, actually adding */
208 parlen--;
209 e_ovwc(LF);
210 lastbrk = 0;
211 len = 0;
212 c = SP; /* Pretend this char was space */
213 #if FX_SFPREF
214 if(fill_plen)
215 { if(cur_dot >= e_dot())
216 cur_dot += fill_plen;
217 /* Better hope no nulls in prefix! */
218 e_sputz(fill_prefix);
219 len = d_curind();
221 #endif /*FX_SFPREF*/
224 done: savloc = cur_dot;
225 e_setcur(); /* Reached paragraph end, set cur_dot temporarily */
226 buf_tmod(begloc-cur_dot); /* So that proper range is marked */
227 e_gosetcur(savloc); /* Then restore original cur_dot */
229 #endif /*FX_FILLREG || FX_FILLPARA*/
231 #if FX_FILLMODE
233 /* EFUN: "Auto Fill Mode" */
234 /* Toggles Auto Fill Mode (a minor mode). */
235 f_fillmode()
236 { register char *cp;
237 int *chballoc();
239 fill_mode = fill_mode ? 0 : 1;
240 if(!fill_trig)
241 { fill_trig = chballoc(128);
242 for(cp = fill_initrig; *cp; ++cp)
243 chbis(fill_trig, *cp);
245 redp(RD_MODE);
248 /* Called by F_INSSELF to handle char insertion in Auto Fill mode */
249 fx_insfill(c)
250 int c;
252 ed_insn(c,exp);
253 if(chbit(fill_trig, c))
254 { fill_cur_line();
260 fill_cur_line()
262 register int foundit, i;
263 chroff lastbrkdot, boldot;
265 boldot = e_boldot();
267 /* First back up to find place to make first break. */
268 e_bwsp();
269 lastbrkdot = e_dot();
270 foundit = 0;
271 for(foundit = 0; foundit >= 0;)
272 { if((i = d_curind()) <= ev_fcolumn)
273 { if(foundit)
274 foundit = -1;
275 else break;
277 else ++foundit;
278 while (!c_wsp (e_rgetc ())) ;
279 e_bwsp();
280 lastbrkdot = e_dot();
281 if(lastbrkdot <= boldot)
282 { lastbrkdot = boldot;
283 break;
287 if(foundit)
288 ed_fill(lastbrkdot, e_eoldot(), 1);
290 #endif /*FX_FILLMODE*/
292 #if IMAGEN
294 #if FX_TEXTMODE
295 /* EFUN: "Text Mode Toggle" (not EMACS) */
296 f_textmode()
298 cur_buf->b_flags ^= B_TEXTMODE;
299 redp(RD_MODE);
301 #endif /*FX_TEXTMODE*/
303 int curr_indent = -1; /* Current indent (for text mode autowrap) */
304 /* (misnomered: actually current column) */
305 chroff best_break; /* Best break point so far */
308 /* Fill-mode version of "Insert Self" */
310 fim_insself(c)
311 int c;
313 register int ind, flags = cur_buf->b_flags;
315 /* In Text mode, auto-wrap happens at spaces after fill column */
316 if (c == SP && flags & B_TEXTMODE && exp == 1 && magic_wrap(c))
317 return;
319 /* In C-mode, tab stops are every 4 columns */
320 else if (c == TAB && flags & B_CMODE &&
321 (ind = magic_backto_bol()) >= 0)
322 ed_indto((ind + 4) & ~3);
323 else
324 { ed_insn(c, exp);
326 /* Keep track of indent, once we have a grip on it */
327 if (last_cmd == INSCMD && curr_indent != -1)
328 { this_cmd = INSCMD; /* Keep the ball rolling */
329 if (c == TAB)
330 curr_indent = ((curr_indent + 8) & ~7)
331 + 8 * (exp - 1);
332 else if (c == '\n')
333 curr_indent = 0;
334 else if (c < SP || c > 0176)
335 curr_indent += (2 * exp);
336 else
337 curr_indent += exp;
342 /* Fill-mode version of "Delete Character" */
344 fim_dchar()
345 { /* In C mode, deleting at BOL should do fake TAB preservation */
346 if (cur_buf->b_flags & B_CMODE)
347 { chroff savdot;
348 register int c, indent;
350 if (e_rgetc() != LF)
351 { /* Only hack this at BOL */
352 e_getc();
353 goto normal;
355 e_getc();
356 savdot = e_dot();
357 indent = 0;
358 while ((c = e_getc()) == SP || c == TAB)
359 if (c == SP)
360 ++indent;
361 else
362 indent = (indent + 8) & ~7;
363 e_rgetc();
364 if (indent >= 4)
365 { ed_delete(savdot, e_dot());
366 ed_indto((indent - 4) & ~3);
367 f_begline(); /* HACK!!!! */
369 else
370 { e_go(savdot);
371 ef_deln(exp);
374 else
375 normal: return (ef_deln(exp));
378 /* Fill-mode version of "Backward Delete Character" */
380 fim_bdchar()
381 { register int ind;
383 /* If in C mode, and deleting into white space at BOL, hack tabs */
384 if (exp == 1 && cur_buf->b_flags & B_CMODE &&
385 (ind = magic_backto_bol()) > 0)
386 ed_indto(ind < 4 ? ind - 1 : ((ind - 4) & ~3));
387 else
388 return (ef_deln (-exp));
391 /* Fill-mode version of "CRLF" */
392 fim_crlf()
393 { register int i;
395 if(e_getc() == LF
396 && exp == 1
397 && e_lblankp() && e_lblankp())
398 { e_gocur();
399 e_gonl();
400 e_setcur();
401 ed_delete(e_dot(), e_eoldot());
403 else
404 { e_gocur();
405 #if IMAGEN
406 if (cur_buf->b_flags & B_TEXTMODE && exp == 1 &&
407 magic_wrap('\n'))
408 return;
409 else
410 #endif /*IMAGEN*/
411 if((i = exp) > 0)
412 do ed_crins();
413 while(--i);
417 /* Do all magic for auto-wrap in Text mode:
418 * return as did wrap (i.e., everything is taken care of)
420 magic_wrap(tc)
421 int tc; /* "trigger char" */
423 register int c, indent, i, nc;
424 chroff savdot, modstart, breakdot;
426 savdot = e_dot();
427 nc = 0;
428 if (last_cmd == INSCMD && curr_indent != -1)
429 { indent = curr_indent; /* Already know our indent */
430 breakdot = best_break;
432 else
434 #ifdef INDENTDEBUG
435 barf2("Full indent calculation");
436 #endif
437 for (nc = 0; (c = e_rgetc()) != EOF && c != '\n'; ++nc)
438 ; /* nc: # chars to look at */
439 if (c == '\n') /* Go back over NL */
440 e_getc();
441 indent = 0;
443 /* Search for last line break point, leaving it in breakdot */
444 breakdot = (chroff)0;
445 while (--nc >= 0)
446 { c = e_getc();
447 if (c == TAB)
448 indent = (indent + 8) & ~7;
449 else if (c < SP || c > 0176)
450 indent += 2;
451 else
452 ++indent;
453 if ((c == SP || c == TAB) &&
454 (breakdot == (chroff)0 || (indent <= ev_fcolumn)))
455 breakdot = e_dot();
459 /* If there is nothing to do, get out */
460 if (indent <= ev_fcolumn)
461 { e_go(savdot);
462 if (tc == SP)
463 { curr_indent = indent;
464 best_break = (chroff)(savdot + 1); /* Remember here, also */
465 this_cmd = INSCMD; /* We do know current indent */
467 else if (tc == '\n')
468 { curr_indent = 0;
469 best_break = (chroff)0;
470 this_cmd = INSCMD;
472 else
473 errbarf("bad trigger");
474 return(0);
477 if (breakdot == (chroff)0)
479 /* No breakpoint found or none needed, just break line at end
481 e_go(savdot);
482 modstart = savdot;
483 e_putc('\n');
485 else
487 /* Get to breakpoint and replace with newline
489 e_go(breakdot);
490 e_rdelc();
491 modstart = e_dot(); /* Remember where changes start */
492 e_putc('\n'); /* Insert line break */
493 e_go(savdot); /* Get back to trigger point */
495 if (e_rgetc() != '\n')
496 { /* If not at line start, */
497 e_getc();
498 e_putc(tc); /* insert trigger character */
500 /* Once again, compute new indent by backing up to BOL */
501 for (nc = 0; (c = e_rgetc()) != EOF && c != '\n'; ++nc)
503 if (c == '\n') /* Go back over NL */
504 e_getc();
505 indent = 0;
506 breakdot = (chroff)0;
507 while (--nc >= 0)
508 { /* Get back to current dot */
509 c = e_getc();
510 if (c == TAB)
511 indent = (indent + 8) & ~7;
512 else if (c < SP || c > 0176)
513 indent += 2;
514 else
515 ++indent;
516 if ((c == SP || c == TAB) &&
517 (breakdot == (chroff)0 || (indent <= ev_fcolumn)))
518 breakdot = e_dot();
520 if (breakdot == (chroff)0) /* If no good break found, use dot */
521 breakdot = e_dot();
522 curr_indent = indent; /* Now we know where we are */
523 if (tc == '\n') /* If trigger was NL */
524 best_break = (chroff)0; /* indent is 0, and no best break */
525 else
526 best_break = breakdot; /* This is best break so far */
528 else
529 { e_getc();
530 curr_indent = 0; /* At line start, no indent */
531 best_break = (chroff)0; /* Do not have a best break so far */
533 ed_setcur();
534 buf_tmat(modstart); /* Alert to potential changes */
535 this_cmd = INSCMD; /* Say we know where we are */
536 return(1);
539 /* Do lots of magic things for C-mode indent:
540 * erase back to BOL iff we are looking back at white space only,
541 * returning the indent level of the original dot
542 * (< 0 means no erasure done)
544 /*#define MYDEBUG /* */
545 #ifdef MYDEBUG
546 reveal(msg, v1, v2, v3)
547 char *msg;
549 char ahint[128];
550 sprintf(ahint, msg, v1, v2, v3);
551 barf2(ahint);
553 #endif
555 magic_backto_bol()
557 chroff savdot;
558 register int c, indent, nc, i;
560 savdot = e_dot();
561 nc = 0;
562 while ((c = e_rgetc()) != EOF && c != LF)
563 { ++nc; /* Count # chars */
564 if (c != SP && c != TAB)
565 { e_go(savdot);
566 #ifdef MYDEBUG
567 reveal("fail: nc: %d", nc);
568 #endif
569 return -1;
572 if (c == LF) /* Go back over the LF */
573 e_getc();
574 indent = 0; /* (zero-based indent) */
575 savdot = e_dot(); /* BOL is now origin for delete */
576 for (i = 1; i <= nc; ++i)
577 if ((c = e_getc()) == SP)
578 ++indent;
579 else /* (tab) */
580 indent = (indent + 8) & ~7;
581 if (nc > 0) /* Don't bother deleting nothing */
582 ed_delete(savdot, e_dot());
583 #ifdef MYDEBUG
584 reveal("indent: %d, nc: %d, foo: %d", indent, nc, 234);
585 #endif
586 return(indent);
588 #endif /*IMAGEN*/
590 #if ICONOGRAPHICS
591 /* Iconographics hack for Auto-Fill mode. Too big and clumsy, but
592 * retained for posterity in case it has some obscure feature.
595 fill_current_line ()
597 chroff startpos, endpos, savepos, limitpos;
598 int i, foundit;
599 SBSTR *savep;
601 foundit = 0;
602 while (d_curind() > ev_fcolumn)
604 foundit = 1;
605 startpos = e_dot ();
606 e_bwsp ();
607 while (d_curind() > ev_fcolumn) /* back up to ends of wds*/
608 { /* until <= fill column */
609 while (!c_wsp (e_rgetc ())) ;
610 e_bwsp ();
612 if (e_dot () == e_boldot ())
613 { /* ding ("Word does not fit in fill column"); */
614 return(0);
616 savep = e_copyn (startpos - e_dot ());
617 e_setcur (); /* ed_delete does gocur */
618 ed_delete (savepos = e_dot (), startpos);
620 f_crlf(); /* Now insert newline */
621 e_sputz(fill_prefix); /* With fill prefix */
622 startpos += e_dot () - savepos;
623 if (d_curind() > ev_fcolumn)
624 { ed_delete (savepos, e_dot ());
625 sb_sins (cur_buf, savep);
626 e_setcur ();
627 ding ("Fill prefix > fill column???");
628 return(0);
630 savepos = e_dot (); /* gun inherited initial whitespace */
631 sb_sins (cur_buf, savep);
632 e_go (savepos);
633 e_fwsp ();
634 if ((limitpos = e_dot ()) > startpos) limitpos = startpos;
635 /* in case rest of line was white */
636 ed_delete (savepos, limitpos);
637 e_gosetcur (startpos + savepos - limitpos);
640 return foundit;
642 #endif /*ICONOGRAPHICS*/