home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / indent-1.9.1-base.tgz / indent-1.9.1-base.tar / fsf / indent / comments.c < prev    next >
C/C++ Source or Header  |  1994-01-29  |  17KB  |  631 lines

  1. /* Copyright (c) 1993,1994, Joseph Arceneaux.  All rights reserved.
  2.  
  3.    This file is subject to the terms of the GNU General Public License as
  4.    published by the Free Software Foundation.  A copy of this license is
  5.    included with this software distribution in the file COPYING.  If you
  6.    do not have a copy, you may obtain a copy by writing to the Free
  7.    Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  8.  
  9.    This software is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details. */
  13.  
  14.  
  15.  
  16. #include "sys.h"
  17. #include "indent.h"
  18.  
  19. /* Check the limits of the comment buffer, and expand as neccessary. */
  20.  
  21. #define CHECK_COM_SIZE \
  22.     if (e_com >= l_com) \
  23.           { \
  24.         register nsize = l_com-s_com+400; \
  25.         combuf = (char *) xrealloc (combuf, nsize); \
  26.         e_com = combuf + (e_com-s_com) + 1; \
  27.         l_com = combuf + nsize - 5; \
  28.         s_com = combuf + 1; \
  29.       }
  30.  
  31. /* The number of comments handled so far. */
  32. int out_coms;
  33.  
  34. /* Output a comment.  `buf_ptr' is pointing to the character after
  35.    the beginning comment delimiter when this is called.  This handles
  36.    both C and C++ comments.
  37.  
  38.    As far as indent is concerned, there are basically two types
  39.    of comments -- those on lines by themselves and those which are
  40.    on lines with other code.  Variables (and the options specifying them)
  41.    affecting the printing of comments are:
  42.  
  43.    `format_comments'                ("fca"):  Ignore newlines in the
  44.        comment and perform filling up to `max_col'.  Double newlines
  45.        indicate paragraph breaks.
  46.  
  47.    `format_col1_comments'           ("fc1"):  Format comments which
  48.        begin in column 1.
  49.  
  50.    `unindent_displace'              ("d"):  The hanging indentation for
  51.        comments which do not appear to the right of code.
  52.  
  53.    `comment_delimiter_on_blankline' ("cdb"):  If set, place the comment
  54.        delimiters on lines by themselves.  This only affects comments
  55.        which are not to the right of code.
  56.  
  57.    `com_ind'                        ("c"):  The column in which to begin
  58.        comments that are to the right of code.
  59.  
  60.    `decl_com_ind'                   ("cd"):  The column in which to begin
  61.        comments that are to the right of declarations.
  62.  
  63.    `else_endif_col'                 ("cp"):  The column in which to begin
  64.        comments to the right of preprocessor directives.
  65.  
  66.    `star_comment_cont'              ("sc"):  Place a star ('*') to the
  67.        left of the comment body.
  68.  
  69.    `comment_max_col'                ("lc"): The length of a comment line.
  70.        Formatted comments which extend past this column will be continued on
  71.        the following line.  If this option is not specified, `max_col' is
  72.        used.
  73.  
  74.    `max_col'                        ("l"):  The length of a line.
  75.  
  76.    */
  77.  
  78. void
  79. print_comment ()
  80. {
  81.   register int column, format;
  82.   enum codes comment_type;
  83.  
  84.   int start_column, save_length, found_column;
  85.   int first_comment_line, right_margin;
  86.   int boxed_comment, stars, blankline_delims, paragraph_break,
  87.       merge_blank_comment_lines;
  88.   char *line_break_ptr = 0;
  89.   char *save_ptr = 0;
  90.   char *text_on_line = 0;
  91.   char *start_delim, *end_delim;
  92.  
  93.   char *line_preamble;
  94.   int line_preamble_length, visible_preamble;
  95.  
  96.   /* Increment the parser stack, as we will store some things
  97.      there for dump_line to use. */
  98.   inc_pstack ();
  99.  
  100.   /* Have to do it this way because this piece of shit program doesn't
  101.      always place the last token code on the stack. */
  102.   if (*(token + 1) == '/')
  103.     comment_type = cplus_comment;
  104.   else
  105.     comment_type = comment;
  106.  
  107.   /* First, decide what kind of comment this is: C++, C, or boxed C.
  108.      Even if this appears to be a normal C comment, we may change our
  109.      minds if we find a star in the right column of the second line,
  110.      in which case that's a boxed comment too. */
  111.   if (comment_type == cplus_comment)
  112.     {
  113.       start_delim = "//";
  114.       line_preamble = "// ";
  115.       line_preamble_length = 3;
  116.       visible_preamble = 1;
  117.       boxed_comment = 0;
  118.       stars = 0;
  119.       blankline_delims = 0;
  120.     }
  121.   else if (*buf_ptr == '*' || *buf_ptr == '-'
  122.        || *buf_ptr == '=' || *buf_ptr == '_')
  123.     /* Boxed comment */
  124.     {
  125.       found_column = start_column = current_column () - 2;
  126.       parser_state_tos->com_col = found_column;
  127.       parser_state_tos->box_com = boxed_comment;
  128.  
  129.       *e_com++ = '/';
  130.       *e_com++ = '*';
  131.       while (1)
  132.     {
  133.       do
  134.         *e_com++ = *buf_ptr++;
  135.       while (*buf_ptr != '*' && buf_ptr < buf_end);
  136.  
  137.       if (*buf_ptr == '*' && *(buf_ptr + 1) == '/')
  138.         {
  139.           if (buf_ptr == buf_end)
  140.         fill_buffer ();
  141.           buf_ptr += 2;
  142.  
  143.           *e_com++ = '*';
  144.           *e_com++ = '/';
  145.           *e_com = '\0';
  146.           parser_state_tos->tos--;
  147.           parser_state_tos->com_col = 1;
  148.           return;
  149.         }
  150.  
  151.       if (buf_ptr == buf_end)
  152.         {
  153.           if (*(buf_ptr - 1) == EOL)
  154.         {
  155.           *(--e_com) = '\0';
  156.           dump_line ();
  157.           parser_state_tos->com_col = 1;
  158.         }
  159.  
  160.           fill_buffer ();
  161.           if (had_eof)
  162.         {
  163.           *e_com++ = '\0';
  164.           parser_state_tos->tos--;
  165.           parser_state_tos->com_col = start_column;
  166.           return;
  167.         }
  168.         }
  169.     }
  170.  
  171. #if 0
  172.       start_delim = "/*";
  173.       end_delim = "*/";
  174.       line_preamble = " ";
  175.       line_preamble_length = 1;
  176.       visible_preamble = 0;
  177.       boxed_comment = 1;
  178.       stars = 0;
  179.       blankline_delims = 0;
  180. #endif
  181.     }
  182.   else
  183.     {
  184.       start_delim = "/*";
  185.       end_delim = "*/";
  186.       line_preamble = 0;
  187.       line_preamble_length = 0;
  188.       visible_preamble = 0;
  189.       boxed_comment = 0;
  190.       stars = star_comment_cont;
  191.       blankline_delims = comment_delimiter_on_blankline;
  192.     }
  193.  
  194.   paragraph_break = 0;
  195.   merge_blank_comment_lines = 0;
  196.   first_comment_line = com_lines;
  197.   right_margin = comment_max_col;
  198.  
  199.   /* Now, compute the correct indentation for this comment
  200.      and whether or not it should be formatted. */
  201.   found_column = current_column () - 2;
  202.   if (boxed_comment)
  203.     {
  204.       start_column = found_column;
  205.       format = 0;
  206.       blankline_delims = 0;
  207.     }
  208.   else
  209.     {
  210.       /* First handle comments which begin the line. */
  211.       if ((s_lab == e_lab) && (s_code == e_code))
  212.     {
  213.       /* This is a top-level comment, not within some code. */
  214.       if (parser_state_tos->ind_level <= 0)
  215.         {
  216.           if (parser_state_tos->col_1)
  217.         {
  218.           format = format_col1_comments;
  219.           start_column = 1;
  220.         }
  221.           else
  222.         {
  223.           format = format_comments;
  224.           start_column = found_column;
  225.         }
  226.         }
  227.       /* Here for comments starting a line, in the middle of code. */
  228.       else
  229.         {
  230.           if (parser_state_tos->col_1)
  231.         {
  232.           format = format_col1_comments;
  233.           start_column = 1;
  234.         }
  235.           else
  236.         {
  237.           format = format_comments;
  238.           start_column = (parser_state_tos->ind_level
  239.                   - unindent_displace + 1);
  240.           if (start_column < 0)
  241.             start_column = 1;
  242.         }
  243.         }
  244.     }
  245.       else
  246.     /* This comment follows code of some sort. */
  247.     {
  248.       int target;
  249.  
  250.       /* First, compute where the comment SHOULD go. */
  251.       if (parser_state_tos->decl_on_line)
  252.         target = decl_com_ind;
  253.       else if (else_or_endif)
  254.         target = else_endif_col;
  255.       else
  256.         target = com_ind;
  257.  
  258.       /* Now determine if the code on the line is short enough
  259.          to allow the comment to begin where it should. */
  260.       if (s_code != e_code)
  261.         start_column = count_columns (compute_code_target (), s_code);
  262.       else
  263.         /* s_lab != e_lab : there is a label here. */
  264.         start_column = count_columns (compute_label_target (), s_lab);
  265.  
  266.       if (start_column < target)
  267.         start_column = target;
  268.       else
  269.         {
  270.           /* If the too-long code is a pre-processor command,
  271.          start the comment 1 space afterwards, otherwise
  272.          start at the next tab mark. */
  273.           if (else_or_endif)
  274.         {
  275.           start_column++;
  276.           else_or_endif = false;
  277.         }
  278.           else
  279.         start_column += (tabsize - (start_column % tabsize) + 1);
  280.         }
  281.  
  282.       format = format_comments;
  283.     }
  284.     }
  285.  
  286.   if (! line_preamble)
  287.     {
  288.       line_preamble_length = 3;
  289.       if (stars)
  290.     {
  291.       line_preamble = " * ";
  292.       visible_preamble = 1;
  293.     }
  294.       else
  295.     {
  296.       line_preamble = "   ";
  297.       visible_preamble = 0;
  298.     }
  299.     }
  300.  
  301.   /* These are the parser stack variables used to communicate
  302.      formatting information to dump_line (). */
  303.   parser_state_tos->com_col = start_column;
  304.   parser_state_tos->box_com = boxed_comment;
  305.   if (boxed_comment)
  306.     {                /* Why is this here?  Could these vars have
  307.                    been reset after the boxed_comment code
  308.                    above?  Check this out.  */
  309.       stars = 0;
  310.       blankline_delims = 0;
  311.     }
  312.  
  313.   /* Output the beginning comment delimiter.  They are both two
  314.      characters long. */
  315.   *e_com++ = *start_delim;
  316.   *e_com++ = *(start_delim + 1);
  317.   column = start_column + 2;
  318.  
  319.   /* If the user specified -cdb, put the delimiter on one line. */
  320.   if (blankline_delims)
  321.     {
  322.       char *p = buf_ptr;
  323.  
  324.       *e_com = '\0';
  325.       dump_line ();
  326.  
  327.       /* Check if the delimiter was already on a line by itself,
  328.      and skip whitespace if formating. */
  329.       while (*p == ' ' || *p == TAB)
  330.     p++;
  331.       if (*p == EOL)
  332.     buf_ptr = p + 1;
  333.       else if (format)
  334.     buf_ptr = p;
  335.       if (buf_ptr >= buf_end)
  336.     fill_buffer ();
  337.  
  338.       column = start_column;
  339.       goto begin_line;
  340.     }
  341.   else if (format)
  342.     {
  343.       *e_com++ = ' ';
  344.       column = start_column + 3;
  345.       while (*buf_ptr == ' ' || *buf_ptr == TAB)
  346.     if (++buf_ptr >= buf_end)
  347.       fill_buffer ();
  348.     }
  349.  
  350.   /* Iterate through the lines of the comment */
  351.   while (! had_eof)
  352.     {
  353.       /* Iterate through the characters on one line */
  354.       while (! had_eof)
  355.     {
  356.       CHECK_COM_SIZE;
  357.  
  358.       switch (*buf_ptr)
  359.         {
  360.         case ' ':
  361.         case TAB:
  362.           /* If formatting, and previous break marker is
  363.              nonexistant, or before text on line, reset
  364.          it to here. */
  365.           if (format && line_break_ptr < text_on_line)
  366.         line_break_ptr = e_com;
  367.  
  368.           if (*buf_ptr == ' ')
  369.         {
  370.           *e_com++ = ' ';
  371.           column++;
  372.         }
  373.           else
  374.         {
  375.           /* Convert the tab to the appropriate number of spaces,
  376.              based on the column we found the comment in, not
  377.              the one we're printing in. */
  378.           int tab_width
  379.             = (tabsize - ((column + found_column - start_column - 1)
  380.                   % tabsize));
  381.           column += tab_width;
  382.           while (tab_width--)
  383.             *e_com++ = ' ';
  384.         }
  385.           break;
  386.  
  387.  
  388.         case EOL:
  389.           /* We may be at the end of a C++ comment */
  390.           if (comment_type == cplus_comment)
  391.         {
  392.           dump_line ();
  393.           buf_ptr++;
  394.           if (buf_ptr >= buf_end)
  395.             fill_buffer ();
  396.  
  397.           parser_state_tos->tos--;
  398.           parser_state_tos->com_col = start_column;
  399.           return;
  400.         }
  401.  
  402.           if (format)
  403.         {
  404.           /* Newline and null are the two characters which
  405.              end an input line, so check here if we need to
  406.              get the next line. */
  407.           buf_ptr++;
  408.           if (buf_ptr >= buf_end)
  409.             fill_buffer ();
  410.  
  411.           /* If this is "\n\n", it's a paragraph break. */
  412.           if (*buf_ptr == EOL || ! text_on_line)
  413.             {
  414.               paragraph_break = 1;
  415.               goto end_line;
  416.             }
  417.  
  418.           /* This is a single newline.  Transform it, and any
  419.              following whitespace into a single blank. */
  420.           line_break_ptr = e_com;
  421.           *e_com++ = ' ';
  422.           column++;
  423.           while (*buf_ptr == TAB || *buf_ptr == ' ')
  424.             if (buf_ptr++ >= buf_end)
  425.               fill_buffer ();
  426.           continue;
  427.         }
  428.           else
  429.         /* We are printing this line "as is", so output it
  430.            and continue on to the next line. */
  431.         goto end_line;
  432.           break;
  433.  
  434.         case '*':
  435.           /* Check if we've reached the end of the comment. */
  436.           if (comment_type == comment)
  437.         {
  438.           if (*(buf_ptr + 1) == '/')
  439.             {
  440.               /* If it's not a boxed comment, put some whitespace
  441.                  before the ending delimiter.  Otherwise, simply
  442.              insert the delimiter. */
  443.               if (! boxed_comment)
  444.             {
  445.               if (text_on_line)
  446.                 {
  447.                   if (blankline_delims)
  448.                 {
  449.                   *e_com = '\0';
  450.                   dump_line ();
  451.                   *e_com++ = ' ';
  452.                 }
  453.                   else
  454.                 /* Insert space before closing delim */
  455.                 if (*(e_com - 1) != ' '&& *(e_com - 1) != TAB)
  456.                   *e_com++ = ' ';
  457.                 }
  458.               /* If no text on line, then line is completely empty
  459.                   or starts with preamble, or is beginning of
  460.                   comment and starts with beginning delimiter. */
  461.               else if (s_com == e_com
  462.                    || *s_com != '/')
  463.                 {
  464.                   e_com = s_com;
  465.                   *e_com++ = ' ';
  466.                 }
  467.               else
  468.                 /* This is case of first comment line.  Test
  469.                    with:
  470.                      if (first_comment_line != com_lines)
  471.                    abort (); */
  472.                 if (*(e_com - 1) != ' ' && *(e_com - 1) != TAB)
  473.                   *e_com++ = ' ';
  474.             }
  475.  
  476.               /* Now insert the ending delimiter */
  477.               *e_com++ = '*';
  478.               *e_com++ = '/';
  479.               *e_com = '\0';
  480.  
  481.               /* Skip any whitespace following the comment.  If
  482.              there is only whitespace after it, print the line. */
  483.               /* NOTE:  We're not printing the line: TRY IT! */
  484.               buf_ptr += 2;
  485.               while (*buf_ptr == ' ' || *buf_ptr == TAB)
  486.             buf_ptr++;
  487.               if (buf_ptr >= buf_end)
  488.               fill_buffer ();
  489.  
  490.               parser_state_tos->tos--;
  491.               parser_state_tos->com_col = start_column;
  492.               return;
  493.             }
  494.  
  495.           /* If this star is on the second line of the
  496.              comment in the same column as the star of the
  497.              beginning delimiter, then consider it
  498.              a boxed comment. */
  499.           if (first_comment_line == com_lines - 1
  500.               && e_com == s_com + line_preamble_length
  501.               && current_column () == found_column + 1)
  502.             {
  503.               line_preamble = " ";
  504.               line_preamble_length = 1;
  505.               boxed_comment = 1;
  506.               format = 0;
  507.               blankline_delims = 0;
  508.               *s_com = ' ';
  509.               *(s_com + 1) = '*';
  510.               e_com = s_com + 2;
  511.               column++;
  512.               break;
  513.             }
  514.         }
  515.           /* If it was not the end of the comment, drop through
  516.              and insert the star on the line. */
  517.  
  518.         default:
  519.           /* Some textual character. */
  520.           text_on_line = e_com;
  521.           *e_com++ = *buf_ptr;
  522.           column++;
  523.           break;
  524.         }
  525.  
  526.  
  527.       /* If we are formatting, check that we haven't exceeded the
  528.          line length.  If we haven't set line_break_ptr, keep going. */
  529.       if (format && column > right_margin && line_break_ptr)
  530.         {
  531.           if (line_break_ptr < e_com - 1)
  532.         {
  533.           *line_break_ptr = '\0';
  534.           save_ptr = line_break_ptr + 1;
  535.           save_length = e_com - save_ptr;
  536.           e_com = line_break_ptr;
  537.  
  538.           /* If we had to go past `right_margin' to print stuff out,
  539.              extend `right_margin' out to this point. */
  540.           if ((column - save_length) > right_margin)
  541.             right_margin = column - save_length;
  542.         }
  543.           else
  544.         *e_com = '\0';
  545.           goto end_line;
  546.         }
  547.  
  548.       buf_ptr++;
  549.       if (buf_ptr == buf_end)
  550.         fill_buffer ();
  551.     }
  552.  
  553.  
  554.     end_line:
  555.       /* Compress pure whitespace lines into newlines. */
  556.       if (! text_on_line
  557.       && ! visible_preamble
  558.       && ! (first_comment_line == com_lines))
  559.     e_com = s_com;
  560.       *e_com = '\0';
  561.       dump_line ();
  562.  
  563.       /* If formatting (paragraph_break is only used for formatted
  564.      comments) and user wants blank lines merged, kill all white
  565.      space after the "\n\n" indicating a paragraph break. */
  566.       if (paragraph_break)
  567.     {
  568.       if (merge_blank_comment_lines)
  569.         while (*buf_ptr == EOL || *buf_ptr == ' ' || *buf_ptr == TAB)
  570.           if (++buf_ptr >= buf_end)
  571.         fill_buffer ();
  572.       paragraph_break = 0;
  573.     }
  574.       else
  575.     {
  576.       /* If it was a paragraph break (`if' clause), we scanned ahead
  577.          one character.  So, here in the `else' clause, advance buf_ptr. */
  578.       buf_ptr++;
  579.       if (buf_ptr >= buf_end)
  580.         fill_buffer ();
  581.     }
  582.  
  583.     begin_line:
  584.       if (had_eof)
  585.     break;
  586.  
  587.       /* Indent the line properly.  If it's a boxed comment, align with
  588.      the '*' in the beginning slash-star and start inserting there.
  589.      Otherwise, insert blanks for alignment, or a star if the
  590.      user specified -sc. */
  591.       if (line_preamble)
  592.     {
  593.       memcpy (e_com, line_preamble, line_preamble_length);
  594.       e_com += line_preamble_length;
  595.       column = start_column + line_preamble_length;
  596.     }
  597.       else
  598.     column = start_column;
  599.       line_break_ptr = 0;
  600.  
  601.       /* If we have broken the line before the end for formatting,
  602.          copy the text after the break onto the beginning of this
  603.      new comment line. */
  604.       if (save_ptr)
  605.     {
  606.       while ((*save_ptr == ' ' || *save_ptr == TAB) && save_length)
  607.         {
  608.           save_ptr++;
  609.           save_length--;
  610.         }
  611.       memcpy (e_com, save_ptr, save_length);
  612.       text_on_line = e_com;
  613.       e_com += save_length;
  614.       /* We only break if formatting, in which cases there
  615.          are no tabs, only spaces.*/
  616.       column += save_length;
  617.       save_ptr = 0;
  618.     }
  619.       else
  620.     {
  621.       while (*buf_ptr == ' ' || *buf_ptr == TAB)
  622.         if (++buf_ptr >= buf_end)
  623.           fill_buffer ();
  624.       text_on_line = 0;
  625.     }
  626.     }
  627.  
  628.   parser_state_tos->tos--;
  629.   parser_state_tos->com_col = start_column;
  630. }
  631.