/* Copyright (c) 1992, Free Software Foundation, Inc.  All rights reserved.

   Copyright (c) 1985 Sun Microsystems, Inc. Copyright (c) 1980 The Regents
   of the University of California. Copyright (c) 1976 Board of Trustees of
   the University of Illinois. All rights reserved.

   Redistribution and use in source and binary forms are permitted
   provided that
   the above copyright notice and this paragraph are duplicated in all such
   forms and that any documentation, advertising materials, and other
   materials related to such distribution and use acknowledge that the
   software was developed by the University of California, Berkeley, the
   University of Illinois, Urbana, and Sun Microsystems, Inc.  The name of
   either University or Sun Microsystems may not be used to endorse or
   promote products derived from this software without specific prior written
   permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
   OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */


#define CHECK_COM_SIZE \
	if (e_com >= l_com) { \
	    register nsize = l_com-s_com+400; \
	    combuf = (char *) xrealloc (combuf, nsize); \
	    e_com = combuf + (e_com-s_com) + 1; \
	    l_com = combuf + nsize - 5; \
	    s_com = combuf + 1; \
	}

/* NAME: pr_comment

FUNCTION: This routine takes care of scanning and printing comments.

ALGORITHM: 1) Decide where the comment should be aligned, and if lines should
   be broken. 2) If lines should not be broken and filled, just copy up to
   end of comment. 3) If lines should be filled, then scan thru input_buffer
   copying characters to com_buf.  Remember where the last blank, tab, or
   newline was.  When line is filled, print up to last blank and continue
   copying.

HISTORY: November 1976	D A Willcox of CAC	Initial coding 12/6/76
    A Willcox of CAC	Modification to handle UNIX-style comments

*/

/* this routine processes comments.  It makes an attempt to keep comments
   from going over the max line length.  If a line is too long, it moves
   everything from the last blank to the next comment line.  Blanks and tabs
   from the beginning of the input line are removed */


#include "sys.h"
#include "indent.h"

int debug_comments;

/* Declared and documented in indent.h.  */
int out_coms;

#ifndef NEW_COMMENTS

print_comment ()
{
  int now_col;			/* column we are in now */
  int adj_max_col;		/* Adjusted max_col for when we decide to
				   spill comments over the right margin */
  char *last_bl;		/* points to the last blank in the output
				   buffer */
  char *t_ptr;			/* used for moving string */
  int unix_comment;		/* tri-state variable used to decide if it is
				   a unix-style comment. 0 means only blanks
				   since /*, 1 means regular style comment, 2
				   means unix style comment */

  int break_delim = comment_delimiter_on_blankline;

  int one_liner = 1;		/* true iff this comment is a one-liner */

  adj_max_col = max_col;
  parser_state_tos->just_saw_decl = 0;
  last_bl = 0;
  parser_state_tos->box_com = false;
  ++out_coms;
  unix_comment = 1;

  if (parser_state_tos->col_1 && !format_col1_comments)
    {
      parser_state_tos->box_com = true;
      parser_state_tos->com_col = 1;
    }
  else
    {
      /* Don't format the comment if it is a "boxed" comment. */
      if (*buf_ptr == '-' || *buf_ptr == '*' || !format_comments)
	{
	  parser_state_tos->box_com = true;
	  break_delim = 0;
	}

      if ((s_lab == e_lab) && (s_code == e_code))
	{
	  /* klg: check only if this line is blank */
	  /* If this (*and previous lines are*) blank, dont put comment way
	     out at left */
	  parser_state_tos->com_col
	    = (parser_state_tos->ind_level - unindent_displace) + 1;
	  adj_max_col = block_comment_max_col;
	  if (parser_state_tos->com_col <= 1)
	    parser_state_tos->com_col = 1 + !format_col1_comments;

	  /* If we have a comment in an old-style (pre-ANSI) parameter
	     declaration, indent it like we would the parameter declaration.
	     For example:
	       int destroy (what) / * N things to destroy.  * / int what;
	  */
	  if (parser_state_tos->in_parameter_declaration
	      && indent_parameters != 0
	      && parser_state_tos->dec_nest == 0)
	    {
	      parser_state_tos->com_col = indent_parameters + 1;
	      parser_state_tos->ind_stmt = 0;
	    }
	}
      else
	{
	  register target_col;
	  break_delim = 0;
	  if (s_code != e_code)
	    target_col = count_spaces (compute_code_target (), s_code);
	  else
	    {
	      target_col = 1;
	      if (s_lab != e_lab)
		target_col = count_spaces (compute_label_target (), s_lab);
	    }
	  parser_state_tos->com_col = parser_state_tos->decl_on_line
	    || parser_state_tos->ind_level == 0 ? decl_com_ind : com_ind;
	  /* If we are already past the position for the comment, put it at
	     the next tab stop.  */
	  if (parser_state_tos->com_col < target_col)
	    parser_state_tos->com_col = ((target_col + (tabsize - 1))
					 & ~(tabsize - 1)) + 1;
	  if (else_or_endif)
	    {
	      parser_state_tos->com_col = else_endif_col;
	      else_or_endif = false;
	      /* We want the comment to appear one space after the #else or
	         #endif.  */
	      if (parser_state_tos->com_col < target_col)
		parser_state_tos->com_col = target_col + 1;
	    }
	  if (parser_state_tos->com_col + 24 > adj_max_col)
	    adj_max_col = parser_state_tos->com_col + 24;
	}
    }

  if (parser_state_tos->box_com)
    {
      parser_state_tos->n_comment_delta = 1 - parser_state_tos->com_col;
#if 0
      buf_ptr[-2] = 0;
      parser_state_tos->n_comment_delta = 1 - count_spaces (1, cur_line);
      buf_ptr[-2] = '/';
#endif
    }
  else
    {
      parser_state_tos->n_comment_delta = 0;
      while (*buf_ptr == ' ' || *buf_ptr == TAB)
	buf_ptr++;
    }

  parser_state_tos->comment_delta = 0;
  *e_com++ = '/';		/* put '/*' into buffer */
  *e_com++ = '*';
  if (*buf_ptr != ' ' && !parser_state_tos->box_com)
    *e_com++ = ' ';

  *e_com = '\0';
  if (troff)
    {
      now_col = 1;
      adj_max_col = 80;
    }
  else
    /* figure what column we would be in if we printed the comment now */
    now_col = count_spaces (parser_state_tos->com_col, s_com);

  /* Start to copy the comment */

  while (1)
    {				/* this loop will go until the comment is
				   copied */
      if (*buf_ptr > 040 && *buf_ptr != '*')
	parser_state_tos->last_nl = 0;

      CHECK_COM_SIZE;
      switch (*buf_ptr)
	{			/* this checks for various spcl cases */
	case 014:		/* check for a form feed */
	  if (!parser_state_tos->box_com)
	    {			/* in a text comment, break the line here */
	      parser_state_tos->use_ff = true;
	      /* fix so dump_line uses a form feed */
	      dump_line ();
	      last_bl = 0;
	      *e_com++ = ' ';
	      *e_com++ = '*';
	      *e_com++ = ' ';
	      while (*++buf_ptr == ' ' || *buf_ptr == TAB);
	    }
	  else
	    {
	      if (++buf_ptr >= buf_end)
		fill_buffer ();
	      *e_com++ = 014;
	    }
	  break;

	case EOL:
	  if (had_eof)
	    {			/* check for unexpected eof */
	      printf ("Unterminated comment\n");
	      *e_com = '\0';
	      dump_line ();
	      return;
	    }

	  one_liner = 0;
	  if (parser_state_tos->box_com || parser_state_tos->last_nl)
	    {			/* if this is a boxed comment, we dont ignore
				   the newline */
	      if (s_com == e_com)
		{
		  *e_com++ = ' ';
		  *e_com++ = ' ';
		}
	      *e_com = '\0';
	      if (!parser_state_tos->box_com && e_com - s_com > 3)
		{
		  if (break_delim == 1 && s_com[0] == '/'
		      && s_com[1] == '*' && s_com[2] == ' ')
		    {
		      char *t = e_com;
		      break_delim = 2;
		      e_com = s_com + 2;
		      *e_com = 0;
		      if (blanklines_before_blockcomments)
			prefix_blankline_requested = 1;
		      dump_line ();
		      e_com = t;
		      s_com[0] = s_com[1] = s_com[2] = ' ';
		    }
		  dump_line ();
		  CHECK_COM_SIZE;
		  *e_com++ = ' ';
		  *e_com++ = ' ';
		}
	      dump_line ();
	      now_col = parser_state_tos->com_col;
	    }
	  else
	    {
	      parser_state_tos->last_nl = 1;
	      if (unix_comment != 1)
		{		/* we not are in unix_style comment */
		  if (unix_comment == 0 && s_code == e_code)
		    {
		      /* if it is a UNIX-style comment, ignore the
		         requirement that previous line be blank for
		         unindention */
		      parser_state_tos->com_col
			= ((parser_state_tos->ind_level - unindent_displace)
			   + ind_size);
		      if (parser_state_tos->com_col <= 1)
			parser_state_tos->com_col = 2;
		    }
		  unix_comment = 2;	/* permanently remember that we are
					   in this type of comment */
		  dump_line ();
		  ++line_no;
		  now_col = parser_state_tos->com_col;
		  *e_com++ = ' ';
		  /* fix so that the star at the start of the line will line
		     up */
		  do		/* flush leading white space */
		    if (++buf_ptr >= buf_end)
		      fill_buffer ();
		  while (*buf_ptr == ' ' || *buf_ptr == TAB);
		  break;
		}
	      if (*(e_com - 1) == ' ' || *(e_com - 1) == TAB)
		last_bl = e_com - 1;
	      /* if there was a space at the end of the last line, remember
	         where it was */
	      else
		{		/* otherwise, insert one */
		  last_bl = e_com;
		  CHECK_COM_SIZE;
		  *e_com++ = ' ';
		  ++now_col;
		}
	    }

	  ++line_no;		/* keep track of input line number */

	  /* Disregard any leading whitespace. */
	  if (!parser_state_tos->box_com)
	    {
	      int nstar = 1;
	      do
		{
		  if (++buf_ptr >= buf_end)
		    fill_buffer ();
		  if (*buf_ptr == '*' && --nstar >= 0)
		    {
		      if (++buf_ptr >= buf_end)
			fill_buffer ();
		      if (*buf_ptr == '/')
			goto end_of_comment;
		    }
		}
	      while (*buf_ptr == ' ' || *buf_ptr == TAB);
	    }
	  else if (++buf_ptr >= buf_end)
	    fill_buffer ();
	  break;		/* end of case for newline */

	case '*':		/* must check for possibility of being at end
				   of comment */
	  if (++buf_ptr >= buf_end)	/* get to next char after * */
	    fill_buffer ();

	  if (unix_comment == 0)/* set flag to show we are not in unix-style
				   comment */
	    unix_comment = 1;

	  if (*buf_ptr == '/')
	    {			/* it is the end!!! */
	    end_of_comment:
	      if (++buf_ptr >= buf_end)
		fill_buffer ();

	      if (*(e_com - 1) != ' ' && !parser_state_tos->box_com)
		{		/* insure blank before end */
		  *e_com++ = ' ';
		  ++now_col;
		}

	      if (break_delim == 1 && !one_liner && s_com[0] == '/'
		  && s_com[1] == '*' && s_com[2] == ' ')
		{
		  char *t = e_com;
		  break_delim = 2;
		  e_com = s_com + 2;
		  *e_com = 0;
		  if (blanklines_before_blockcomments)
		    prefix_blankline_requested = 1;
		  dump_line ();
		  e_com = t;
		  s_com[0] = s_com[1] = s_com[2] = ' ';
		}

	      if (break_delim == 2 && e_com > s_com + 3
	      /* now_col > adj_max_col - 2 && !parser_state_tos->box_com */ )
		{
		  *e_com = '\0';
		  dump_line ();
		  now_col = parser_state_tos->com_col;
		}

	      CHECK_COM_SIZE;
	      *e_com++ = '*';
	      *e_com++ = '/';
	      *e_com = '\0';
	      return;
	    }
	  else
	    {			/* handle isolated '*' */
	      *e_com++ = '*';
	      ++now_col;
	    }
	  break;

	default:		/* we have a random char */
	  if (unix_comment == 0 && *buf_ptr != ' ' && *buf_ptr != TAB)
	    unix_comment = 1;	/* we are not in unix-style comment */

	  *e_com = *buf_ptr++;
	  if (buf_ptr >= buf_end)
	    fill_buffer ();

	  if (*e_com == TAB)	/* keep track of column */
	    now_col = now_col + tabsize - (now_col - 1) % tabsize;
	  else if (*e_com == '\b')	/* this is a backspace */
	    --now_col;
	  else
	    ++now_col;

	  if (*e_com == ' ' || *e_com == TAB)
	    last_bl = e_com;
	  /* remember we saw a blank */

	  ++e_com;
	  if (now_col > adj_max_col
	      && !parser_state_tos->box_com
	      && unix_comment == 1
	      && e_com[-1] > ' ')
	    {
	      /* the comment is too long, it must be broken up */
	      if (break_delim == 1 && s_com[0] == '/'
		  && s_com[1] == '*' && s_com[2] == ' ')
		{
		  char *t = e_com;
		  break_delim = 2;
		  e_com = s_com + 2;
		  *e_com = 0;
		  if (blanklines_before_blockcomments)
		    prefix_blankline_requested = 1;
		  dump_line ();
		  e_com = t;
		  s_com[0] = s_com[1] = s_com[2] = ' ';
		}
	      if (last_bl == 0)
		{		/* we have seen no blanks */
		  last_bl = e_com;	/* fake it */
		  *e_com++ = ' ';
		}
	      *e_com = '\0';	/* print what we have */
	      *last_bl = '\0';
	      while (last_bl > s_com && last_bl[-1] < 040)
		*--last_bl = 0;
	      e_com = last_bl;
	      dump_line ();

	      *e_com++ = ' ';	/* add blanks for continuation */
	      *e_com++ = ' ';
	      *e_com++ = ' ';

	      t_ptr = last_bl + 1;
	      last_bl = 0;
	      if (t_ptr >= e_com)
		{
		  while (*t_ptr == ' ' || *t_ptr == TAB)
		    t_ptr++;
		  while (*t_ptr != '\0')
		    {		/* move unprinted part of comment down in
				   buffer */
		      if (*t_ptr == ' ' || *t_ptr == TAB)
			last_bl = e_com;
		      *e_com++ = *t_ptr++;
		    }
		}
	      *e_com = '\0';
	      /* recompute current position */
	      now_col = count_spaces (parser_state_tos->com_col, s_com);
	    }
	  break;
	}
    }
}

#else  /* New Comment code -- UNDER CONSTRUCTION */

/* Output a comment.  `buf_ptr' is pointing to the character after
   the beginning comment delimiter when this is called.  This handles
   both C and C++ comments.

   As far as indent is concerned, there are basically two types
   of comments -- those on lines by themselves and those which are
   on lines with other code.  Variables (and the options specifying them)
   affecting the printing of comments are:

   `format_comments'                ("fca"):  Ignore newlines in the
       comment and perform filling up to `max_col'.  Double newlines
       indicate paragraph breaks.

   `format_col1_comments'           ("fc1"):  Format comments which
       begin in column 1.

   `unindent_displace'              ("d"):  The hanging indentation for
       comments which do not appear to the right of code.

   `comment_delimiter_on_blankline' ("cdb"):  If set, place the comment
       delimiters on lines by themselves.  This only affects comments
       which are not to the right of code.

   `com_ind'                        ("c"):  The column in which to begin
       comments that are to the right of code.

   `decl_com_ind'                   ("cd"):  The column in which to begin
       comments that are to the right of declarations.

   `else_endif_col'                 ("cp"):  The column in which to begin
       comments to the right of preprocessor directives.

   `star_comment_cont'              ("sc"):  Place a star ('*') to the
       left of the comment body.

   `max_col'                        ("l"):  The length of a line.  Formatted
       comments which extend past this column will be continued on the
       following line.

   `block_comment_max_col'          ("lc"): Unused.

   `blanklines_before_blockcomments'("nbbb"): Unused.

   */

void
print_comment ()
{
  register int tab_increment;
  register int column, format;
  enum codes comment_type;

  int start_column, save_length, found_column;
  int first_comment_line, right_margin;
  int boxed_comment, stars, blankline_delims, paragraph_break,
      merge_blank_comment_lines;
  char *line_break_ptr = 0;
  char *save_ptr = 0;
  char *text_on_line = 0;
  char *start_delim, *end_delim;

  char *line_preamble;
  int line_preamble_length;

  /* Increment the parser stack, as we will store some things
     there for dump_line to use. */
  inc_pstack ();

  /* Have to do it this way because this piece of shit program doesn't
     always place the last token code on the stack. */
  if (*(token + 1) == '/')
    comment_type = cplus_comment;
  else
    comment_type = comment;

  /* First, decide what kind of comment this is: C++, C, or boxed C.
     Even if this appears to be a normal C comment, we may change our
     minds if we find a star in the right column of the second line,
     in which case that's a boxed comment too. */
  if (comment_type == cplus_comment)
    {
      start_delim = "//";
      line_preamble = "// ";
      line_preamble_length = 3;
      boxed_comment = 0;
      stars = 0;
      blankline_delims = 0;
    }
  else if (*buf_ptr == '*' || *buf_ptr == '-')
    {
      start_delim = "/*";
      end_delim = "*/";
      line_preamble = " ";
      line_preamble_length = 1;
      boxed_comment = 1;
      stars = 0;
      blankline_delims = 0;
    }
  else
    {
      start_delim = "/*";
      end_delim = "*/";
      line_preamble = 0;
      line_preamble_length = 0;
      boxed_comment = 0;
      stars = star_comment_cont;
      blankline_delims = comment_delimiter_on_blankline;
    }

  paragraph_break = 0;
  merge_blank_comment_lines = 0;
  first_comment_line = com_lines;
  right_margin = max_col;

  /* Now, compute the correct indentation for this comment
     and whether or not it should be formatted. */
  found_column = current_column () - 2;
  if (boxed_comment)
    {
      start_column = found_column;
      format = 0;
      blankline_delims = 0;
    }
  else
    {
      /* First handle comments which begin the line. */
      if ((s_lab == e_lab) && (s_code == e_code))
	{
	  /* This is a top-level comment, not within some code. */
	  if (parser_state_tos->ind_level <= 0)
	    {
	      if (parser_state_tos->col_1)
		{
		  format = format_col1_comments;
		  start_column = 1;
		}
	      else
		{
		  format = format_comments;
		  start_column = found_column;
		}
	    }
	  /* Here for comments starting a line, in the middle of code. */
	  else
	    {
	      if (parser_state_tos->col_1)
		{
		  format = format_col1_comments;
		  start_column = 1;
		}
	      else
		{
		  format = format_comments;
		  start_column = (parser_state_tos->ind_level
				  - unindent_displace + 1);
		  if (start_column < 0)
		    start_column = 1;
		}
	    }
	}
      else
	/* This comment follows code of some sort. */
	{
	  int target;

	  /* First, computer where the comment SHOULD go. */
	  if (parser_state_tos->decl_on_line)
	    target = decl_com_ind;
	  else if (else_or_endif)
	    target = else_endif_col;
	  else
	    target = com_ind;

	  /* Now determine if the code on the line is short enough
	     to allow the comment to begin where it should. */
	  if (s_code != e_code)
	    start_column = count_spaces (compute_code_target (), s_code);
	  else
	    /* s_lab != e_lab : there is a label here. */
	    start_column = count_spaces (compute_label_target (), s_lab);

	  if (start_column < target)
	    start_column = target;
	  else
	    {
	      /* If the too-long code is a pre-processor command,
		 start the comment 1 space afterwards, otherwise
		 start at the next tab mark. */
	      if (else_or_endif)
		{
		  start_column++;
		  else_or_endif = false;
		}
	      else
		start_column += (tabsize - (start_column % tabsize) + 1);
	    }

	  format = format_comments;
	}
    }

  if (! line_preamble)
    {
      line_preamble_length = 3;
      if (stars)
	line_preamble = " * ";
      else
	line_preamble = "   ";
    }

  /* These are the parser stack variables used to communicate
     formatting information to dump_line (). */
  parser_state_tos->com_col = start_column;
  parser_state_tos->box_com = boxed_comment;
  parser_state_tos->comment_delta = 0;
  parser_state_tos->n_comment_delta = 0;
  if (boxed_comment)
    {
      stars = 0;
      blankline_delims = 0;
    }

  /* Output the beginning comment delimiter.  They are both two
     characters long. */
  memcpy (e_com, start_delim, 2);
  e_com += 2;
  column = start_column + 2;

  /* If the user specified -cdb, put the delimiter on one line. */
  if (blankline_delims)
    {
      char *p = buf_ptr;

      *e_com = '\0';
      dump_line ();

      /* Check if the delimiter was already on a line by itself,
	 and skip whitespace if formating. */
      while ((*p == ' ' || *p == TAB) && p < buf_end)
	p++;
      if (*p == EOL)
	buf_ptr = p + 1;
      else if (format)
	buf_ptr = p;
      if (buf_ptr >= buf_end)
	fill_buffer ();

      column = start_column;
      goto begin_line;
    }
  else if (format)
    {
      *e_com++ = ' ';
      column = start_column + 3;
      while (*buf_ptr == ' ' || *buf_ptr == TAB)
	if (++buf_ptr >= buf_end)
	  fill_buffer ();
    }

  /* Iterate through the lines of the comment */
  while (1)
    {
      /* Iterate through the characters on one line */
      while (1)
	{
	  CHECK_COM_SIZE;

	  switch (*buf_ptr)
	    {
	    case ' ':
	    case TAB:
	      /* If formatting, and previous break marker is
	         nonexistant, or before text on line, reset
		 it to here. */
	      if (format && line_break_ptr < text_on_line)
		line_break_ptr = e_com;

	      if (*buf_ptr == ' ')
		{
		  *e_com++ = ' ';
		  column++;
		}
	      else
		{
		  /* Convert the tab to the appropriate number of spaces,
		     based on the column we found the comment in, not
		     the one we're printing in. */
		  int tab_width
		    = (tabsize - ((column + found_column - start_column - 1)
				  % tabsize));
		  column += tab_width;
		  while (tab_width--)
		    *e_com++ = ' ';
		}
	      break;

	    case EOL:
	      /* We may be at the end of a C++ comment */
	      if (comment_type == cplus_comment)
		{
		  dump_line ();
		  buf_ptr++;
		  if (buf_ptr == buf_end)
		    fill_buffer ();

		  parser_state_tos->tos--;
		  parser_state_tos->com_col = start_column;
		  return;
		}

	      if (format)
		{
		  /* Newline and null are the two characters which
		     end a line, so check here if we need to
		     advance to the next line. */
		  if (++buf_ptr == buf_end)
		    fill_buffer ();
		  if (*buf_ptr == EOL)
		    {
		      paragraph_break = 1;
		      postfix_blankline_requested = 1;
		      goto end_line;
		    }

		  /* This is a single newline.  Transform it, and any
		     following whitespace into a single blank. */
		  line_break_ptr = e_com;
		  *e_com++ = ' ';
		  column++;
		  while (*buf_ptr == TAB || *buf_ptr == ' ')
		    if (++buf_ptr == buf_end)
		      fill_buffer ();
		  continue;
		}
	      else
		/* We are printing this line "as is", so output it
		   and continue on to the next line. */
		goto end_line;
	      break;

	    case '*':
	      /* Check if we've reached the end of the comment. */
	      if (comment_type == comment)
		{
		  if (*(buf_ptr + 1) == '/')
		    {
		      /* If it's a boxed comment, skip this and simply
			 insert the delimiter on the line.  Otherwise, put
			 some whitespace before the delimiter. */
		      if (! boxed_comment)
			{
			  if (text_on_line)
			    {
			      if (blankline_delims)
				{
				  *e_com = '\0';
				  dump_line ();
				  *e_com++ = ' ';
				}
			      else
				if (*(e_com - 1) != ' ')
				  *e_com++ = ' ';
			    }
			  else
			    e_com = s_com + 1;
			}

		      *e_com++ = '*';
		      *e_com++ = '/';
		      *e_com = '\0';

		      /* Skip any whitespace following the comment.  If
			 there is only whitespace after it, print the line. */
		      buf_ptr += 2;
		      while (*buf_ptr == ' ' || *buf_ptr == TAB)
			buf_ptr++;
		      if (buf_ptr >= buf_end)
			fill_buffer ();

		      parser_state_tos->tos--;
		      parser_state_tos->com_col = start_column;
		      return;
		    }

		  /* If this star is on the second line of the
		     comment in the same column as the star of the
		     beginning delimiter, then consider it
		     a boxed comment. */
		  if (first_comment_line == com_lines - 1
		      && e_com == s_com + line_preamble_length
		      && current_column () == start_column + 1)
		    {
		      line_preamble = " ";
		      line_preamble_length = 1;
		      boxed_comment = 1;
		      format = 0;
		      blankline_delims = 0;
		      *s_com = ' ';
		      *(s_com + 1) = '*';
		      e_com = s_com + 2;
		      column++;
		      break;
		    }
		}
	      /* If it was not the end of the comment, drop through
	         and insert the star on the line. */

	    default:
	      /* Some textual character. */
	      text_on_line = e_com;
	      *e_com++ = *buf_ptr;
	      column++;
	      break;
	    }

	  /* If we are formatting, check that we haven't exceeded the
	     line length.  If we haven't set line_break_ptr, keep going. */
	  if (format && column >= right_margin && line_break_ptr)
	    {
	      if (line_break_ptr < e_com - 1)
		{
		  *line_break_ptr = '\0';
		  save_ptr = line_break_ptr + 1;
		  save_length = e_com - save_ptr;
		  e_com = line_break_ptr;

		  /* If we had to go past `right_margin' to print stuff out,
		     extend `right_margin' out to this point. */
		  if ((column - save_length) > right_margin)
		    right_margin = column - save_length;
		}
	      else
		*e_com = '\0';
	      goto end_line;
	    }

	  buf_ptr++;
	}


    end_line:
      buf_ptr++;
      if (buf_ptr >= buf_end)
	fill_buffer ();
      *e_com = '\0';
      dump_line ();

      /* If formatting (paragraph_break is only used for formatted
	 comments) and user wants blank lines merged, kill all white
	 space after the "\n\n" indicating a paragraph break. */
      if (paragraph_break)
	{
	  if (merge_blank_comment_lines)
	    while (*buf_ptr == EOL || *buf_ptr == ' ' || *buf_ptr == TAB)
	      if (++buf_ptr >= buf_end)
		fill_buffer ();
	  paragraph_break = 0;
	}


    begin_line:
      /* Indent the line properly.  If it's a boxed comment, align with
	 the '*' in the beginning slash-star and start inserting there.
	 Otherwise, insert blanks for alignment, or a star if the
	 user specified -sc. */
      if (line_preamble)
	{
	  memcpy (e_com, line_preamble, line_preamble_length);
	  e_com += line_preamble_length;
	  column = start_column + line_preamble_length;
	}
      else
	column = start_column;
      line_break_ptr = 0;

      /* If we have broken the line before the end for formatting,
         copy the text after the break onto the beginning of this
	 new comment line. */
      if (save_ptr)
	{
	  while ((*save_ptr == ' ' || *save_ptr == TAB) && save_length)
	    {
	      save_ptr++;
	      save_length--;
	    }
	  memcpy (e_com, save_ptr, save_length);
	  text_on_line = e_com;
	  e_com += save_length;
	  /* We only break if formatting, in which cases there
	     are no tabs, only spaces.*/
	  column += save_length;
	  save_ptr = 0;
	}
      else
	{
	  while (*buf_ptr == ' ' || *buf_ptr == TAB)
	    if (++buf_ptr >= buf_end)
	      fill_buffer ();
	  text_on_line = 0;
	}
    }
}
#endif /* New comment code */
