home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / jove-4.16-src.tgz / tar.out / bsd / jove / c.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  18KB  |  786 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. /* Contains commands for C mode.  Paren matching routines are in here. */
  9.  
  10. #include "jove.h"
  11. #include "re.h"
  12. #include "c.h"
  13. #include "jctype.h"
  14. #include "disp.h"
  15. #include "delete.h"
  16. #include "insert.h"
  17. #include "fmt.h"
  18. #include "marks.h"
  19. #include "misc.h"
  20. #include "move.h"
  21. #include "paragraph.h"
  22.  
  23. private void
  24.     FindMatch proto((int));
  25.  
  26. private bool
  27. backslashed(lp, cpos)
  28. register char    *lp;
  29. register int    cpos;
  30. {
  31.     register int    cnt = 0;
  32.  
  33.     while (cpos > 0 && lp[--cpos] == '\\')
  34.         cnt += 1;
  35.     return (cnt % 2) != 0;
  36. }
  37.  
  38. private char    *p_types = "(){}[]";
  39. private int    mp_kind;
  40. #define MP_OKAY        0
  41. #define MP_MISMATCH    1
  42. #define MP_UNBALANCED    2
  43. #define MP_INCOMMENT    3
  44.  
  45. void
  46. mp_error()
  47. {
  48.     switch (mp_kind) {
  49.     case MP_MISMATCH:
  50.         message("[Mismatched parentheses]");
  51.         break;
  52.  
  53.     case MP_UNBALANCED:
  54.         message("[Unbalanced parenthesis]");
  55.         break;
  56.  
  57.     case MP_INCOMMENT:
  58.         message("[Inside a comment]");
  59.         break;
  60.  
  61.     case MP_OKAY:
  62.     default:
  63.         return;
  64.     }
  65.     rbell();
  66. }
  67.  
  68. /* Search from the current position for the paren that matches p_type.
  69.    Search in the direction dir.  If can_mismatch is YES then it is okay
  70.    to have mismatched parens.  If stop_early is YES then when an open
  71.    paren is found at the beginning of a line, it is assumed that there
  72.    is no point in backing up further.  This is so when you hit tab or
  73.    LineFeed outside, in-between procedure/function definitions, it won't
  74.    sit there searching all the way to the beginning of the file for a
  75.    match that doesn't exist.  {forward,backward}-s-expression are the
  76.    only ones that insist on getting the "true" story. */
  77.  
  78. Bufpos *
  79. m_paren(p_type, dir, can_mismatch, can_stop)
  80. char    p_type;
  81. register int    dir;
  82. bool    can_mismatch;
  83. bool    can_stop;
  84. {
  85.     static Bufpos    ret;
  86.     Bufpos    savedot;
  87.     struct RE_block    re_blk;
  88.     int    count = 0;
  89.     register char    c = '\0';    /* avoid uninitialized complaint from gcc -W */
  90.     char
  91.         p_match,    /* kind of paren matching p_type */
  92.         quote_c = '\0';
  93.     register int    c_char;
  94.     int    in_comment = -1;    /* -1, YES, or NO */
  95.     bool    stopped = NO;
  96.  
  97.     REcompile(MajorMode(CMODE)? "[(){}[\\]/\"']" : "[(){}[\\]\"]",
  98.         YES, &re_blk);
  99.     {
  100.         char    *cp = strchr(p_types, p_type);
  101.  
  102.         if (cp == NULL)
  103.             complain("[Cannot match %c's]", p_type);
  104.         p_match = cp[dir];
  105.     }
  106.     DOTsave(&savedot);
  107.  
  108.     /* To make things a little faster I avoid copying lines into
  109.        linebuf by setting curline and curchar by hand.  Warning:
  110.        this is slightly to very risky.  When I did this there were
  111.        lots of problems with procedures that expect the contents of
  112.        curline to be in linebuf. */
  113.     do {
  114.         Bufpos    *sp = docompiled(dir, &re_blk);
  115.         register char    *lp;
  116.  
  117.         if (sp == NULL)
  118.             break;
  119.         lp = lbptr(sp->p_line);
  120.  
  121.         curline = sp->p_line;
  122.         curchar = sp->p_char;    /* here's where I cheat */
  123.  
  124.         c_char = curchar;
  125.         if (dir == FORWARD)
  126.             c_char -= 1;
  127.         if (backslashed(lp, c_char))
  128.             continue;
  129.         c = lp[c_char];
  130.         /* check if this is a comment (if we're not inside quotes) */
  131.         if (quote_c == '\0' && c == '/') {
  132.             int    new_ic = in_comment;    /* -1, YES, or NO */
  133.  
  134.             /* close comment */
  135.             if ((c_char != 0) && lp[c_char - 1] == '*') {
  136.                 new_ic = (dir == FORWARD) ? NO : YES;
  137.                 if (new_ic == NO && in_comment == -1) {
  138.                     count = 0;
  139.                     quote_c = '\0';
  140.                 }
  141.             } else if (lp[c_char + 1] == '*') {
  142.                 new_ic = (dir == FORWARD) ? YES : NO;
  143.                 if (new_ic == NO && in_comment == -1) {
  144.                     count = 0;
  145.                     quote_c = '\0';
  146.                 }
  147.             }
  148.             in_comment = new_ic;
  149.         }
  150.         if (in_comment == YES)
  151.             continue;
  152.         if (c == '"' || c == '\'') {
  153.             if (quote_c == c)
  154.                 quote_c = '\0';
  155.             else if (quote_c == '\0')
  156.                 quote_c = c;
  157.         }
  158.         if (quote_c != '\0')
  159.             continue;
  160.         if (jisopenp(c)) {
  161.             count += dir;
  162.             if (c_char == 0 && can_stop && count >= 0) {
  163.                 stopped = YES;
  164.                 break;
  165.             }
  166.         } else if (jisclosep(c)) {
  167.             count -= dir;
  168.         }
  169.     } while (count >= 0);
  170.  
  171.     ret.p_line = curline;
  172.     ret.p_char = curchar;
  173.  
  174.     curline = savedot.p_line;
  175.     curchar = savedot.p_char;    /* here's where I undo it */
  176.  
  177.     if (count >= 0)
  178.         mp_kind = MP_UNBALANCED;
  179.     else if (c != p_match)
  180.         mp_kind = MP_MISMATCH;
  181.     else
  182.         mp_kind = MP_OKAY;
  183.  
  184.     /* If we stopped (which means we were allowed to stop) and there
  185.        was an error, we clear the error so no error message is printed.
  186.        An error should be printed ONLY when we are sure about the fact,
  187.        namely we didn't stop prematurely HOPING that it was the right
  188.        answer. */
  189.     if (stopped && mp_kind != MP_OKAY) {
  190.         mp_kind = MP_OKAY;
  191.         return NULL;
  192.     }
  193.     if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch))
  194.         return &ret;
  195.     return NULL;
  196. }
  197.  
  198. private void
  199. do_expr(dir, skip_words)
  200. register int    dir;
  201. bool    skip_words;
  202. {
  203.     register char    syntax = (dir == FORWARD) ? C_BRA : C_KET;
  204.  
  205.     if (dir == BACKWARD)
  206.         b_char(1);
  207.     for (;;) {
  208.         char    c = linebuf[curchar];
  209.  
  210.         if (!skip_words && jisident(c)) {
  211.             for (;;) {
  212.                 if (dir == FORWARD? c == '\0' : bolp())
  213.                         break;
  214.                 curchar += dir;
  215.                 if (!jisident(linebuf[curchar])) {
  216.                     if (dir == BACKWARD)
  217.                         curchar += 1;
  218.                     break;
  219.                 }
  220.             }
  221.             break;
  222.         }
  223. /*
  224.  * BUG ALERT! The following test ought not to recognise brackets inside
  225.  * comments or quotes
  226.  */
  227.         if (has_syntax(c, syntax)) {
  228.             FindMatch(dir);
  229.             break;
  230.         }
  231.         f_char(dir);
  232.         if (eobp() || bobp())
  233.             return;
  234.     }
  235. }
  236.  
  237. void
  238. FSexpr()
  239. {
  240.     register int    num = arg_value();
  241.  
  242.     if (num < 0) {
  243.         negate_arg();
  244.         BSexpr();
  245.     }
  246.     while (--num >= 0)
  247.         do_expr(FORWARD, NO);
  248. }
  249.  
  250. void
  251. FList()
  252. {
  253.     register int    num = arg_value();
  254.  
  255.     if (num < 0) {
  256.         negate_arg();
  257.         BList();
  258.     }
  259.     while (--num >= 0)
  260.         do_expr(FORWARD, YES);
  261. }
  262.  
  263. void
  264. BSexpr()
  265. {
  266.     register int    num = arg_value();
  267.  
  268.     if (num < 0) {
  269.         negate_arg();
  270.         FSexpr();
  271.     }
  272.     while (--num >= 0)
  273.         do_expr(BACKWARD, NO);
  274. }
  275.  
  276. void
  277. BList()
  278. {
  279.     register int    num = arg_value();
  280.  
  281.     if (num < 0) {
  282.         negate_arg();
  283.         FList();
  284.     }
  285.     while (--num >= 0)
  286.         do_expr(BACKWARD, YES);
  287. }
  288.  
  289. void
  290. BUpList()
  291. {
  292.     register int    num = arg_value();
  293.     Bufpos    *mp;
  294.  
  295.     if (num < 0) {
  296.         negate_arg();
  297.         FDownList();
  298.     }
  299.     while (--num >= 0) {
  300.         mp = m_paren(')', BACKWARD, YES, YES);
  301.         if (mp == NULL)
  302.             mp_error();
  303.         else
  304.             SetDot(mp);
  305.     }
  306. }
  307.  
  308. void
  309. FDownList()
  310. {
  311.     register int    num = arg_value();
  312.     Bufpos    *sp;
  313.     char    *sstr = "[{([\\])}]";
  314.  
  315.     if (num < 0) {
  316.         negate_arg();
  317.         BUpList();
  318.     }
  319.     while (--num >= 0) {
  320. /*
  321.  * BUG ALERT! The following test ought not to recognise brackets inside
  322.  * comments or quotes
  323.  */
  324.         sp = dosearch(sstr, FORWARD, YES);
  325.         if (sp == NULL || jisclosep(lcontents(sp->p_line)[sp->p_char - 1]))
  326.             complain("[No contained expression]");
  327.         SetDot(sp);
  328.     }
  329. }
  330.  
  331. /* Move to the matching brace or paren depending on the current position
  332.    in the buffer. */
  333.  
  334. private void
  335. FindMatch(dir)
  336. int    dir;
  337. {
  338.     register Bufpos    *bp;
  339.     register char    c = linebuf[curchar];
  340.  
  341.     if (strchr(p_types, c) == NULL || backslashed(linebuf, curchar))
  342.         complain((char *)NULL);
  343.     if (dir == FORWARD)
  344.         f_char(1);
  345.     bp = m_paren(c, dir, YES, NO);
  346.     if (dir == FORWARD)
  347.         b_char(1);
  348.     if (bp != NULL)
  349.         SetDot(bp);
  350.     mp_error();    /* if there is an error the user wants to
  351.                know about it */
  352. }
  353.  
  354. #define ALIGN_ARGS    (-1)
  355.  
  356. /* If CArgIndent == ALIGN_ARGS then the indentation routine will
  357.    indent a continued line by lining it up with the first argument.
  358.    Otherwise, it will indent CArgIndent characters past the indent
  359.    of the first line of the procedure call. */
  360.  
  361. int    CArgIndent = ALIGN_ARGS;    /* VAR: how to indent arguments to C functions */
  362.  
  363. /* indent for C code */
  364. Bufpos *
  365. c_indent(brace)
  366. bool    brace;
  367. {
  368.     Bufpos    *bp;
  369.     int    new_indent = 0,
  370.         current_indent,
  371.         increment = brace? 0 : CIndIncrmt;
  372.  
  373.     /* Find matching paren, which may be a mismatch now.  If it
  374.        is not a matching curly brace then it is a paren (most likely).
  375.        In that case we try to line up the arguments to a procedure
  376.        or inside an of statement. */
  377.     if ((bp = m_paren('}', BACKWARD, YES, YES)) != NULL) {
  378.         Bufpos    save;
  379.         int    matching_indent;
  380.  
  381.         DOTsave(&save);
  382.         SetDot(bp);        /* go to matching paren */
  383.         ToIndent();
  384.         matching_indent = calc_pos(linebuf, curchar);
  385.         SetDot(bp);
  386.         switch (linebuf[curchar]) {
  387.         case '{':
  388.             new_indent = matching_indent;
  389.             if (!bolp()) {
  390.                 b_char(1);
  391.                 /* If we're not within the indent then we
  392.                    can assume that there is either a C keyword
  393.                    line DO on the line before the brace, or
  394.                    there is a parenthesized expression.  If
  395.                    that's the case we want to go backward
  396.                    over that to the beginning of the expression
  397.                    so that we can get the correct indent for
  398.                    this matching brace.  This handles wrapped
  399.                    if statements, etc. */
  400.                 if (!within_indent()) {
  401.                     Bufpos    savematch;
  402.  
  403.                     savematch = *bp;
  404.  
  405.                     do_expr(BACKWARD, NO);
  406.                     ToIndent();
  407.                     new_indent = calc_pos(linebuf, curchar);
  408.  
  409.                     /* do_expr() calls b_paren, which
  410.                        returns a pointer to a structure,
  411.                        and that pointer is in BP so we
  412.                        have to save away the matching
  413.                        paren and restore it in the
  414.                        following line ... sigh */
  415.                     *bp = savematch;
  416.                 }
  417.             }
  418.             if (!brace)
  419.                 new_indent += (increment - (new_indent % increment));
  420.             break;
  421.  
  422.         case '(':
  423.             if (CArgIndent == ALIGN_ARGS) {
  424.                 f_char(1);
  425.                 new_indent = calc_pos(linebuf, curchar);
  426.             } else
  427.                 new_indent = matching_indent + CArgIndent;
  428.             break;
  429.         }
  430.         SetDot(&save);
  431.     }
  432.  
  433.     /* new_indent is the "correct" place to indent.  Now we check to
  434.        see if what we consider as the correct place to indent is to
  435.        the LEFT of where we already are.  If it is, and we are NOT
  436.        handling a brace, then we assume that the person wants to tab
  437.        in further than what we think is right (for some reason) and
  438.        so we allow that. */
  439.  
  440.     ToIndent();
  441.     current_indent = calc_pos(linebuf, curchar);
  442.     if (!brace && new_indent <= current_indent)
  443.         new_indent = current_indent + (increment - (current_indent % increment));
  444.     Bol();
  445.     DelWtSpace();            /* nice uniform Tabs*Space* */
  446.     n_indent(new_indent);
  447.  
  448.     return bp;
  449. }
  450.  
  451. private void
  452. re_indent(incr)
  453. int    incr;
  454. {
  455.     LinePtr    l1, l2, lp;
  456.     int    c1, c2;
  457.     Mark    *m = CurMark();
  458.     Bufpos    savedot;
  459.  
  460.     DOTsave(&savedot);
  461.     l1 = curline;
  462.     c1 = curchar;
  463.     l2 = m->m_line;
  464.     c2 = m->m_char;
  465.     (void) fixorder(&l1, &c1, &l2, &c2);
  466.     for (lp = l1; lp != l2->l_next; lp = lp->l_next) {
  467.         int    indent;
  468.  
  469.         SetLine(lp);
  470.         ToIndent();
  471.         indent = calc_pos(linebuf, curchar);
  472.         if (indent != 0 || linebuf[0] != '\0')
  473.             n_indent(indent + incr);
  474.     }
  475.     SetDot(&savedot);
  476. }
  477.  
  478. void
  479. LRShift()
  480. {
  481.     re_indent(-arg_or_default(CIndIncrmt));
  482. }
  483.  
  484. void
  485. RRShift()
  486. {
  487.     re_indent(arg_or_default(CIndIncrmt));
  488. }
  489.  
  490. #ifdef CMT_FMT
  491.  
  492. char    CmtFmt[80] = "/*%n%! * %c%!%n */";    /* VAR: comment format */
  493.  
  494. /* Strip leading and trailing white space.  Skip over any imbedded '\n's. */
  495.  
  496. private void
  497. strip_c(from, to)
  498. char    *from,
  499.     *to;
  500. {
  501.     register char
  502.         *fr_p = from,
  503.         *to_p = to,
  504.         c;
  505.  
  506.     while ((c = *fr_p) == '\n' || jiswhite(c))
  507.         fr_p += 1;
  508.     while ((c = *fr_p) != '\0') {
  509.         if (c != '\n')
  510.             *to_p++ = c;
  511.         fr_p += 1;
  512.     }
  513.     while (to_p > to && jiswhite(to_p[-1]))
  514.         to_p -= 1;
  515.     *to_p = '\0';
  516. }
  517.  
  518. # define CMT_STR_BOUND    20
  519.  
  520. private char    open_c[CMT_STR_BOUND],    /* the open comment format string */
  521.         open_pat[CMT_STR_BOUND],    /* the search pattern for open comment */
  522.         l_header[CMT_STR_BOUND],    /* the prefix for each comment line */
  523.         l_trailer[CMT_STR_BOUND],    /* the suffix ... */
  524.         close_c[CMT_STR_BOUND],
  525.         close_pat[CMT_STR_BOUND];
  526.  
  527. private bool    nl_in_close_c;
  528.  
  529. /* Fill in the data structures above from the format string.  Don't return
  530.    if there's trouble. */
  531.  
  532. private void
  533. parse_cmt_fmt()
  534. {
  535.  
  536.     static char    *const component[] = {
  537.         open_c,
  538.         l_header,
  539.         l_trailer,
  540.         close_c
  541.     };
  542.     register char    *fmtp = CmtFmt;
  543.     register char    *const *c_body = component,
  544.             *body_p = *c_body,
  545.             *body_limit = body_p + CMT_STR_BOUND - 1;
  546.     char    c;
  547.     int    comp_no = 0;
  548.  
  549.     /* pick apart the comment string */
  550.     nl_in_close_c = NO;
  551.     while ((c = *fmtp++) != '\0') {
  552.         if (c == '%') {
  553.             switch(c = *fmtp++) {
  554.             case 'n':
  555.                 switch (comp_no) {
  556.                 case 0:
  557.                     break;
  558.                 case 3:
  559.                     nl_in_close_c = YES;
  560.                     break;
  561.                 default:
  562.                     complain("%%n not allowed in line header or trailer: %s",
  563.                         fmtp - 2);
  564.                     /* NOTREACHED */
  565.                 }
  566.                 c = '\n';
  567.                 break;
  568.             case 't':
  569.                 c = '\t';
  570.                 break;
  571.             case '%':
  572.                 break;
  573.             case '!':
  574.             case 'c':
  575.                 if (++comp_no == elemsof(component))
  576.                     complain("too many components");
  577.                 if ((c=='c') != (comp_no==2))
  578.                     complain("wrong separator: %%%c", c);
  579.                 *body_p++ = '\0';
  580.                 body_p = *++c_body;
  581.                 body_limit = body_p + CMT_STR_BOUND - 1;
  582.                 continue;
  583.             default:
  584.                 complain("[Unknown comment escape: %%%c]", c);
  585.                 /*NOTREACHED*/
  586.             }
  587.         }
  588.         if (body_p >= body_limit)
  589.             complain("component too long");
  590.         *body_p++ = c;
  591.     }
  592.     *body_p = '\0';
  593.     while (++comp_no != elemsof(component))
  594.         **++c_body = '\0';
  595.     /* make search patterns */
  596.     strip_c(open_c, open_pat);
  597.     strip_c(close_c, close_pat);
  598. }
  599.  
  600. void
  601. Comment()
  602. {
  603.     int    saveRMargin,
  604.         indent_pos;
  605.     bool    found_close;
  606.     size_t    header_len,
  607.         trailer_len;
  608.     register char    *cp;
  609.     Bufpos    open_c_pt,
  610.         close_c_pt,
  611.         tmp_bp,
  612.         *match_o,
  613.         *match_c;
  614.     Mark    *entry_mark,    /* end of comment (we may terminate it) */
  615.         *open_c_mark,    /* start of comment (reference to curmark) */
  616.         *savedot;
  617.  
  618.     parse_cmt_fmt();
  619.     /* Figure out if we're "inside" a comment.
  620.      * First look back for opening comment symbol.
  621.      */
  622.     if ((match_o = dosearch(open_pat, BACKWARD, NO)) == NULL)
  623.         complain("No opening %s to match to.", open_pat);
  624.     open_c_pt = *match_o;
  625.     if ((match_c = dosearch(close_pat, BACKWARD, NO)) != NULL
  626.     && inorder(open_c_pt.p_line, open_c_pt.p_char,
  627.             match_c->p_line, match_c->p_char))
  628.         complain("[Must be between %s and %s to re-format]",
  629.             open_pat, close_pat);
  630.  
  631.     /* Now look forward for closing comment symbol.
  632.      * This involves looking forward for the next opening too.
  633.      */
  634.     if ((match_o = dosearch(open_pat, FORWARD, NO)) != NULL) {
  635.         tmp_bp = *match_o;
  636.         match_o = &tmp_bp;
  637.     }
  638.     match_c = dosearch(close_pat, FORWARD, NO);
  639.  
  640.     /* If we found the right close comment symbol, we format
  641.      * up to it; otherwise we format up to dot.  We have found the
  642.      * close if we found (looking forward) a close not preceded by
  643.      * an open.
  644.      */
  645.     found_close = match_c != NULL
  646.         && (match_o == NULL
  647.             || inorder(match_c->p_line, match_c->p_char,
  648.                 match_o->p_line, match_o->p_char));
  649.  
  650.     if (found_close) {
  651.         close_c_pt = *match_c;
  652.     } else {
  653.         close_c_pt.p_line = curline;
  654.         close_c_pt.p_char = curchar;
  655.     }
  656.  
  657.     SetDot(&open_c_pt);
  658.     set_mark();    /* user visible mark! */
  659.     open_c_mark = curmark;
  660.     indent_pos = calc_pos(linebuf, curchar);
  661.  
  662.     /* move to end; delete close if it exists */
  663.     SetDot(&close_c_pt);
  664.     CopyRegion();
  665.     if (found_close)
  666.         del_char(BACKWARD, (int)strlen(close_pat), NO);
  667.     entry_mark = MakeMark(curline, curchar);
  668.  
  669.     /* always separate the comment body from anything preceeding it */
  670.     ToMark(open_c_mark);
  671.     LineInsert(1);
  672.     DelWtSpace();
  673.     Bol();
  674.  
  675.     /* insert comment open string */
  676.     for (cp = open_c; *cp!='\0'; cp++) {
  677.         if (*cp == '\n') {
  678.             if (!eolp())
  679.                 LineInsert(1);
  680.             else
  681.                 line_move(FORWARD, 1, NO);
  682.         } else if (jiswhite(*cp)) {
  683.             if (linebuf[curchar] != *cp)
  684.                 insert_c(*cp, 1);
  685.         } else {
  686.             /* Since we matched the open comment string
  687.              * on this line, we don't need to worry about
  688.              * crossing line boundaries.
  689.              */
  690.             curchar += 1;
  691.         }
  692.     }
  693.     savedot = MakeMark(curline, curchar);
  694.  
  695.     /* We need to strip the line header pattern of leading
  696.      * white space since we need to match the line after all of
  697.      * its leading whitespace is gone.
  698.      */
  699.     for (cp = l_header; *cp && (jiswhite(*cp)); cp++)
  700.         ;
  701.     header_len = strlen(cp);
  702.     trailer_len = strlen(l_trailer);
  703.  
  704.     /* Strip each comment line of the open and close comment strings
  705.        before reformatting it. */
  706.  
  707.     do {
  708.         Bol();
  709.         DelWtSpace();
  710.         if (header_len && strncmp(linebuf, cp, header_len)==0)
  711.             del_char(FORWARD, (int)header_len, NO);
  712.         if (trailer_len) {
  713.             Eol();
  714.             if ((size_t)curchar > trailer_len
  715.             && strncmp(&linebuf[curchar - trailer_len],
  716.                       l_trailer, trailer_len)==0)
  717.                 del_char(BACKWARD, (int)trailer_len, NO);
  718.         }
  719.         if (curline->l_next != NULL)
  720.             line_move(FORWARD, 1, NO);
  721.         else
  722.             break;
  723.     } while (curline != entry_mark->m_line->l_next);
  724.  
  725.     /* Now that comment decoration is gone, use normal fill
  726.      * routine to format body.
  727.      */
  728.  
  729.     do_set_mark(savedot->m_line, savedot->m_char);    /* user visible mark! */
  730.     DelMark(savedot);
  731.     ToMark(entry_mark);
  732.     saveRMargin = RMargin;
  733.     RMargin = saveRMargin - strlen(l_header) -
  734.           strlen(l_trailer) - indent_pos + 2;
  735.     do_rfill(NO);    /* justify from mark through point */
  736.     RMargin = saveRMargin;
  737.     PopMark();    /* get back to the start of the comment; discard mark */
  738.  
  739.     /* redecorate newly filled comment text */
  740.  
  741.     do {
  742.         if (curline != open_c_mark->m_line->l_next) {
  743.             Bol();
  744.             n_indent(indent_pos);
  745.             ins_str(l_header);
  746.         }
  747.         Eol();
  748.         if (nl_in_close_c || (curline != entry_mark->m_line))
  749.             ins_str(l_trailer);
  750.         if (curline->l_next != NULL)
  751.             line_move(FORWARD, 1, NO);
  752.         else
  753.             break;
  754.     } while (curline != entry_mark->m_line->l_next);
  755.  
  756.     /* handle the close comment symbol */
  757.     if (curline == entry_mark->m_line->l_next) {
  758.         line_move(BACKWARD, 1, NO);
  759.         Eol();
  760.     }
  761.     DelMark(entry_mark);
  762.     DelWtSpace();
  763.     /* if the addition of the close symbol would cause the line
  764.      * to be too long, put the close symbol on the next line.
  765.      */
  766.     if (!nl_in_close_c
  767.     && (int)strlen(close_c) + calc_pos(linebuf, curchar) > RMargin)
  768.     {
  769.         LineInsert(1);
  770.         n_indent(indent_pos);
  771.     }
  772.     for (cp = close_c; *cp; cp++) {
  773.         if (*cp == '\n') {
  774.             LineInsert(1);
  775.             n_indent(indent_pos);
  776.         } else
  777.             insert_c(*cp, 1);
  778.     }
  779.     ExchPtMark();
  780.     Eol();
  781.     del_char(FORWARD, 1, NO);
  782.     this_cmd = UNDOABLECMD;    /* allow yank-pop to undo */
  783. }
  784.  
  785. #endif /* CMT_FMT */
  786.