home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / jove414s.zip / c.c < prev    next >
C/C++ Source or Header  |  1991-07-07  |  18KB  |  766 lines

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