Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/indent/indent.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/* Copyright (c) 1999, 2000 Carlo Wood.  All rights reserved.
 * Copyright (c) 1994, 1996, 1997 Joseph Arceneaux.  All rights reserved.
 * 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.
 *
 * Updates;
 * 2002-08-05: Matthias <[email protected]> and Eric Lloyd <[email protected]>
 *             Added support for -brf to place function opening brace after function
 *             declaration.
 */

#include "sys.h"

#if defined (HAVE_UNISTD_H)
#include <unistd.h>
#endif
#ifdef PRESERVE_MTIME
#include <time.h>
#ifdef HAVE_UTIME_H
#include <utime.h>
#elif defined(HAVE_SYS_UTIME_H)
#include <sys/utime.h>
#endif
#endif
#include <sys/stat.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include "indent.h"
#include "backup.h"
#include "io.h"
#include "globs.h"
#include "parse.h"
#include "comments.h"
#include "args.h"
#include "output.h"

RCSTAG_CC ("$Id: indent.c,v 1.77 2002/10/28 20:00:56 david Exp $");

/* Round up P to be a multiple of SIZE. */

#ifndef ROUND_UP
#define ROUND_UP(p, size) (((unsigned long) (p) + (size) - 1) & ~((size) - 1))
#endif

/* Stuff that needs to be shared with the rest of indent.
 * Documented in indent.h.
 */

char           * labbuf                      = NULL;
char           * s_lab                       = NULL;
char           * e_lab                       = NULL;
char           * l_lab                       = NULL;
char           * codebuf                     = NULL;
char           * s_code                      = NULL;
char           * e_code                      = NULL;
char           * l_code                      = NULL;
char           * combuf                      = NULL;
char           * s_com                       = NULL;
char           * e_com                       = NULL;
char           * l_com                       = NULL;
char           * s_code_corresponds_to       = NULL;
buf_ty           save_com;
char           * bp_save                     = NULL;
char           * be_save                     = NULL;
int              code_lines                  = 0;
int              line_no                     = 0;
int              break_comma                 = 0;
int              n_real_blanklines           = 0;
int              prefix_blankline_requested  = 0;
codes_ty         prefix_blankline_requested_code;
int              postfix_blankline_requested  = 0;
codes_ty         postfix_blankline_requested_code;
char           * in_name                     = 0; /* Points to current input file name */
file_buffer_ty * current_input               = 0; /* Points to the current input buffer */
int              embedded_comment_on_line    = 0; /* True if there is an embedded comment on this code line */
int              else_or_endif               = 0;
int            * di_stack                    = NULL; /* structure indentation levels */
int              di_stack_alloc              = 0; /* Currently allocated size of di_stack.  */
int              squest                      = 0; /* when this is positive, we have seen a ? without
                                                * the matching : in a <c>?<s>:<s> construct */
unsigned long    in_prog_size   = 0U;
char           * in_prog        = NULL;
int              break_line     = 0;

/* The position that we will line the current line up with when it comes time
 * to print it (if we are lining up to parentheses).  */

static int       paren_target   = 0;

#ifdef DEBUG
int            debug = 1;
#endif

/******************************************************************************/
static void check_code_size(void)
{
    if (e_code >= l_code)                               
    {                                                   
        int nsize = l_code - s_code + 400;               
        codebuf   = (char *) xrealloc (codebuf, nsize);  
        e_code    = codebuf + (e_code - s_code) + 1; 
        l_code    = codebuf + nsize - 5; 
        s_code    = codebuf + 1; 
    }
}

/******************************************************************************/
static void check_lab_size(void)
{
    if (e_lab >= l_lab)
    {
        int nsize  = l_lab - s_lab + 400;               
        labbuf = (char *) xrealloc (labbuf, nsize); 
        e_lab  = labbuf + (e_lab - s_lab) + 1;        
        l_lab  = labbuf + nsize - 5;                
        s_lab  = labbuf + 1;                        
    }
}


/******************************************************************************/
static INLINE void need_chars (
    buf_ty * bp,
    int      needed)
{
    int current_size = (bp->end - bp->ptr);

    if ((current_size + needed) >= bp->size)
    {
        bp->size = ROUND_UP (current_size + needed, 1024);
        bp->ptr = xrealloc (bp->ptr, bp->size);
        if (bp->ptr == NULL)
        {
            fatal (_("Ran out of memory"), 0);
        }

        bp->end = bp->ptr + current_size;
    }
}

/******************************************************************************/
/* Compute the length of the line we will be outputting. */

int output_line_length (void)
{
    int code_length = 0;
    int com_length = 0;
    int length;

    if (s_lab == e_lab)
    {
        length = 0;
    }
    else
    {
        length = count_columns (compute_label_target (), s_lab, EOL) - 1;
    }

    if (s_code != e_code)
    {
        int code_col = compute_code_target (paren_target);

        code_length = count_columns (code_col, s_code, EOL) - code_col;
    }

    if (s_com != e_com)
    {
        int com_col = parser_state_tos->com_col;

        com_length = count_columns (com_col, s_com, EOL) - com_col;
    }

    if (code_length != 0)
    {
        length += compute_code_target(paren_target) - 1 + code_length;

        if (embedded_comment_on_line)
        {
            length += com_length;
        }
    }

    return length;
}

/******************************************************************************/
static void copy_id(
    const codes_ty   type_code,
    BOOLEAN        * force_nl,
    exit_values_ty * file_exit_value,
    const bb_code_ty can_break)
{
    char           * t_ptr;
    
    if (parser_state_tos->want_blank)
    {
        set_buf_break (bb_ident, paren_target);
        *e_code++ = ' ';
    }
    else if (can_break)
    {
        set_buf_break (can_break, paren_target);
    }

    if (s_code == e_code)
    {
        s_code_corresponds_to = token;
    }

    for (t_ptr = token; t_ptr < token_end; ++t_ptr)
    {
        check_code_size();
        *e_code++ = *t_ptr;
    }

    *e_code = '\0'; /* null terminate code sect */

    parser_state_tos->want_blank = true;

    /* Handle the options -nsaf, -nsai and -nsaw */

    if ((type_code == sp_paren) &&
        ((!settings.space_after_if && (*token == 'i')) ||
         (!settings.space_after_for && (*token == 'f')) ||
         (!settings.space_after_while && (*token == 'w'))))
    {
        parser_state_tos->want_blank = false;
    }

    /* If the token is one of the GNU gettext macro's '_' or 'N_'
     * then we don't want a blank */

    if ((((token_end - token) == 1) && (*token == '_')) ||
        (((token_end - token) == 2) && (*token == 'N') &&
         (token[1] == '_')))
    {
        parser_state_tos->want_blank = false;
    }

    /* If the token is va_dcl, it appears without a semicolon, so we
     * need to pretend that one was there.  */

    if (((token_end - token) == 6) && (strncmp (token, "va_dcl", 6) == 0))
    {
        parser_state_tos->in_or_st = 0;
        parser_state_tos->just_saw_decl--;
        parser_state_tos->in_decl = false;

        do
        {
            if (parse (semicolon) != total_success) 
            {
                *file_exit_value = indent_error;
            }
        } while(0);
                
        *force_nl = true;
    }
}

/******************************************************************************/
static void handle_token_form_feed(void)
{
    parser_state_tos->use_ff = true;        /* a form feed is treated
                                             * much like a newline */
    dump_line (true, &paren_target);
    parser_state_tos->want_blank = false;
}

/******************************************************************************
 * 2002-06-13 D.Ingamells Reset force_nl if the line is dumped.
 */
static void handle_token_newline(
    BOOLEAN * force_nl)
{
            
    if (s_lab != e_lab && *s_lab == '#')
    {
        dump_line (true, &paren_target);

        if (s_code == e_code)
        {
            parser_state_tos->want_blank = false;
        }

        *force_nl = false;
    }
    else
    {
        if ( ( (parser_state_tos->last_token != comma) || 
               !settings.leave_comma ||
               !break_comma || 
               (parser_state_tos->p_l_follow > 0) ||
               parser_state_tos->block_init || 
               (s_com != e_com)) &&
             ( ( (parser_state_tos->last_token != rbrace) ||
                 !(settings.braces_on_struct_decl_line && 
                   parser_state_tos->in_decl))))
        {
            /* Attempt to detect the newline before a procedure name,
             * and if e.g., K&R style, leave the procedure on the
             * same line as the type. */

            if (!settings.procnames_start_line && 
                (s_lab == e_lab) &&
                (parser_state_tos->last_token != lparen) &&
                (parser_state_tos->last_token != semicolon) &&
                (parser_state_tos->last_token != comma) &&
                (parser_state_tos->last_rw == rw_decl) &&
                (parser_state_tos->last_rw_depth == 0) &&
                (!parser_state_tos->block_init) &&
                (parser_state_tos->in_decl))
            {
                /* Put a space between the type and the procedure name,
                 * unless it was a pointer type and the user doesn't
                 * want such spaces after '*'. */

                if (!((e_code > s_code) &&
                      (e_code[-1] == '*')))
                {
                    parser_state_tos->want_blank = true;
                }
            }

            if (!parser_state_tos->in_stmt ||
                (s_com != e_com) || 
                embedded_comment_on_line)
            {
                dump_line (true, &paren_target);

                if (s_code == e_code)
                {
                    parser_state_tos->want_blank = false;
                }

                *force_nl = false;
            }
        }
    }

    /* If we were on the line with a #else or a #endif, we aren't
     * anymore.  */

    else_or_endif = false;
    ++line_no;              /* keep track of input line number */
}

/******************************************************************************/
static void handle_token_lparen(
    BOOLEAN        * force_nl,
   BOOLEAN        * sp_sw,
   int            * dec_ind)
{
    char lparen = *token;
    
    /* Braces in initializer lists should be put on new lines. This is
     * necessary so that -gnu does not cause things like char
     * *this_is_a_string_array[] = { "foo", "this_string_does_not_fit",
     * "nor_does_this_rather_long_string" } which is what happens
     * because we are trying to line the strings up with the
     * parentheses, and those that are too long are moved to the right
     * an ugly amount.
     *
     * However, if the current line is empty, the left brace is
     * already on a new line, so don't molest it.
     */

    if ((*token == '{') && ((s_code != e_code) ||
                              (s_com  != e_com)  ||
                              (s_lab  != e_lab)))
    {
        dump_line (true, &paren_target);

        /* Do not put a space before the '{'.  */

        parser_state_tos->want_blank = false;
    }

    /* Count parens so we know how deep we are.  */
    
    ++parser_state_tos->p_l_follow;
    
    if (parser_state_tos->p_l_follow >= parser_state_tos->paren_indents_size)
    {
        parser_state_tos->paren_indents_size *= 2;
        parser_state_tos->paren_indents =
                (short *) xrealloc ((char *) parser_state_tos->paren_indents,
                                    parser_state_tos->paren_indents_size *
                                    sizeof (short));
    }

    parser_state_tos->paren_depth++;

    if (parser_state_tos->want_blank &&
        (*token != '[') &&
        ( (parser_state_tos->last_token != ident) ||
          settings.proc_calls_space ||
          (parser_state_tos->its_a_keyword &&
           (!parser_state_tos->sizeof_keyword || settings.blank_after_sizeof))))
    {
        set_buf_break (bb_proc_call, paren_target);
        *e_code++ = ' ';
        *e_code = '\0';     /* null terminate code sect */
    }
    else
    {
        set_buf_break (bb_proc_call, paren_target);
    }

    if (parser_state_tos->in_decl && !parser_state_tos->block_init)
    {
        if ((*token != '[') && !buf_break_used)
        {
            while ((e_code - s_code) < *dec_ind)
            {
                check_code_size();
                set_buf_break (bb_dec_ind, paren_target);
                *e_code++ = ' ';
            }

            *e_code++ = token[0];
            parser_state_tos->ind_stmt = false;
        }
        else
        {
            *e_code++ = token[0];
        }
    }
    else
    {
        *e_code++ = token[0];
    }

    if (settings.parentheses_space && *token != '[')
    {
        *e_code++ = ' ';
    }

    parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1] =
            e_code - s_code;

    if (*sp_sw && (parser_state_tos->p_l_follow == 1) &&
        settings.extra_expression_indent &&
        (parser_state_tos->paren_indents[0] < 2 * settings.ind_size))
    {
        parser_state_tos->paren_indents[0] = 2 * settings.ind_size;
    }

    parser_state_tos->want_blank = false;

    if ((parser_state_tos->in_or_st == 1) && *token == '(')
    {
        /* this is a kludge to make sure that declarations will be
         * correctly aligned if proc decl has an explicit type on it, i.e.
         * "int a(x) {..." */

        parse_lparen_in_decl ();

        /* Turn off flag for structure decl or initialization.  */
        
        parser_state_tos->in_or_st = 0;
    }

    /* For declarations, if user wants all fn decls broken, force that
     * now. 
     */
    
    if ((*token == '(')                   && 
        settings.break_function_decl_args &&
        parser_state_tos->in_stmt         && 
        parser_state_tos->in_decl         &&
        (parser_state_tos->paren_depth == 1))
    {
        dump_line(true, &paren_target);
        *force_nl = false;
        
        paren_target = parser_state_tos->paren_depth * settings.ind_size + 1;
        parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1] = -paren_target;
    }

    if (parser_state_tos->sizeof_keyword)
    {
        parser_state_tos->sizeof_mask |= 1 << parser_state_tos->p_l_follow;
    }

    /* The '(' that starts a cast can never be preceded by an
     * indentifier or decl.  */

    if ((parser_state_tos->last_token == decl) ||
        ((parser_state_tos->last_token == ident) &&
         (parser_state_tos->last_rw != rw_return)))
    {
        parser_state_tos->noncast_mask |=
                1 << parser_state_tos->p_l_follow;
    }
    else
    {
        parser_state_tos->noncast_mask &=
                ~(1 << parser_state_tos->p_l_follow);
    }
}

/******************************************************************************/
static void handle_token_rparen(
   BOOLEAN        * force_nl,
   BOOLEAN        * sp_sw,
   codes_ty       * hd_type,
   BOOLEAN        * last_token_ends_sp,
   exit_values_ty * file_exit_value)
{
            
    parser_state_tos->paren_depth--;
    
#if 1
    /* For declarations, if user wants close of fn decls broken, force that
     * now. 
     */
    if ((*token == ')')                   &&
        settings.break_function_decl_args_end &&
        !parser_state_tos->in_or_st       &&
         parser_state_tos->in_stmt        && 
        parser_state_tos->in_decl         &&
        (parser_state_tos->paren_depth == 0))
    {
        if ((s_code != e_code) || (s_lab != e_lab) || (s_com != e_com))
        {
            dump_line(true, &paren_target);
        }
        
        paren_target = parser_state_tos->paren_depth * settings.ind_size;
        parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1] = paren_target;
        parser_state_tos->ind_stmt = 0;
    }
#endif

    if (parser_state_tos->
        cast_mask & (1 << parser_state_tos->
                     p_l_follow) & ~parser_state_tos->sizeof_mask)
    {
        parser_state_tos->last_u_d = true;
        parser_state_tos->cast_mask &=
                (1 << parser_state_tos->p_l_follow) - 1;
        if (!parser_state_tos->cast_mask && settings.cast_space)
        {
            parser_state_tos->want_blank = true;
        }
        else
        {
            parser_state_tos->want_blank = false;
            parser_state_tos->can_break = bb_cast;
        }
    }
    else if (parser_state_tos->in_decl &&
             !parser_state_tos->block_init &&
             (parser_state_tos->paren_depth == 0))
    {
        parser_state_tos->want_blank = true;
    }

    parser_state_tos->sizeof_mask &=
            (1 << parser_state_tos->p_l_follow) - 1;

    if (--parser_state_tos->p_l_follow < 0)
    {
        parser_state_tos->p_l_follow = 0;
        WARNING (_("Extra %c"),
                 (unsigned long) *((unsigned char *) token), 0);
    }

    /* if the paren starts the line, then indent it */

    if (e_code == s_code)
    {
        int level = parser_state_tos->p_l_follow;

        parser_state_tos->paren_level = level;
        if (level > 0)
        {
            paren_target = -parser_state_tos->paren_indents[level - 1];
        }
        else
        {
            paren_target = 0;
        }
    }

    if (settings.parentheses_space && *token != ']')
    {
        *e_code++ = ' ';
    }

    *e_code++ = token[0];

    /* check for end of if (...), or some such */

    if (*sp_sw && (parser_state_tos->p_l_follow == 0))
    {
        /* Indicate that we have just left the parenthesized expression
         * of a while, if, or for, unless we are getting out of the
         * parenthesized expression of the while of a do-while loop.
         * (do-while is different because a semicolon immediately
         * following this will not indicate a null loop body).  */

        if (parser_state_tos->p_stack[parser_state_tos->tos] != dohead)
        {
            *last_token_ends_sp = 2;
        }

        *sp_sw = false;
        *force_nl = true;    /* must force newline after if */
        parser_state_tos->last_u_d = true;  /* inform lexi that a
                                             * following operator is
                                             * unary */
        parser_state_tos->in_stmt = false;  /* dont use stmt
                                             * continuation
                                             * indentation */

        if (parse (*hd_type) != total_success)
        {
            *file_exit_value = indent_error;
        }
    }

    /* this should ensure that constructs such as main(){...} and
     * int[]{...} have their braces put in the right place
     */
    
    parser_state_tos->search_brace = settings.btype_2;
}

/******************************************************************************/
static void handle_token_unary_op(
   int            * dec_ind,
   const bb_code_ty can_break)
{
    char           * t_ptr;
    
    if (parser_state_tos->want_blank)
    {
        set_buf_break (bb_unary_op, paren_target);
        *e_code++ = ' ';
        *e_code = '\0';     /* null terminate code sect */
    }
    else if (can_break)
    {
        set_buf_break (can_break, paren_target);
    }

    {
        char *res = token;
        char *res_end = token_end;

        /* if this is a unary op in a declaration, we should
         * indent this token */

        if ((parser_state_tos->paren_depth == 0) &&
            parser_state_tos->in_decl && !buf_break_used &&
            !parser_state_tos->block_init)
        {
            while ((e_code - s_code) < (*dec_ind - (token_end - token)))
            {
                check_code_size();
                set_buf_break (bb_dec_ind, paren_target);
                *e_code++ = ' ';
            }

            parser_state_tos->ind_stmt = false;
        }

        for (t_ptr = res; t_ptr < res_end; ++t_ptr)
        {
            check_code_size();
            *e_code++ = *t_ptr;
        }

        *e_code = '\0';     /* null terminate code sect */
    }

    parser_state_tos->want_blank = false;
}
/******************************************************************************/
static void handle_token_binary_op(
   const bb_code_ty can_break)
{
    char           * t_ptr;
            
    if (parser_state_tos->want_blank
        || (e_code > s_code && *e_code != ' '))
    {
        set_buf_break (bb_binary_op, paren_target);
        *e_code++ = ' ';
        *e_code = '\0';     /* null terminate code sect */
    }
    else if (can_break)
    {
        set_buf_break (can_break, paren_target);
    }

    {
        char *res = token;
        char *res_end = token_end;

        for (t_ptr = res; t_ptr < res_end; ++t_ptr)
        {
            check_code_size();
            *e_code++ = *t_ptr;     /* move the operator */
        }
    }

#if 1
    if (*token == '=')
    {
        parser_state_tos->in_decl = false;
        
    }
#endif
    
    parser_state_tos->want_blank = true;
}
/******************************************************************************/
static void handle_token_postop(void)
{
    *e_code++ = token[0];
    *e_code++ = token[1];
    parser_state_tos->want_blank = true;
}

/******************************************************************************/
static void handle_token_question(
   const bb_code_ty can_break)
{
    squest++;               /* this will be used when a later colon
                             * appears so we can distinguish the
                             * <c>?<n>:<n> construct */

    if (parser_state_tos->want_blank)
    {
        set_buf_break (bb_question, paren_target);
        *e_code++ = ' ';
    }
    else if (can_break)
    {
        set_buf_break (can_break, paren_target);
    }

    *e_code++ = '?';
    parser_state_tos->want_blank = true;
    *e_code = '\0'; /* null terminate code sect */
}

/******************************************************************************/
static void handle_token_casestmt(
   BOOLEAN        * scase,
   exit_values_ty * file_exit_value)
{
    *scase = true;           /* so we can process the later colon
                              * properly */
    do
    {
        if (parse (casestmt) != total_success)
        {
            *file_exit_value = indent_error;
        }
    } while(0);       /* Let parser know about it */
            
}

/******************************************************************************/
static void handle_token_colon(
   BOOLEAN        * scase,
   BOOLEAN        * force_nl,
   int            * dec_ind,
   const bb_code_ty can_break)
{
    char           * t_ptr;

    if (squest > 0)
    {
        /* it is part of the <c> ? <n> : <n> construct */

        --squest;
        if (parser_state_tos->want_blank)
        {
            set_buf_break (bb_colon, paren_target);
            *e_code++ = ' ';
        }
        else if (can_break)
        {
            set_buf_break (can_break, paren_target);
        }

        *e_code++ = ':';
        *e_code = '\0';     /* null terminate code sect */
        parser_state_tos->want_blank = true;
    }
    else
    {
        /*            __ e_code
         *           |
         * "  private:\n"                     C++, treat as label.
         *  ^^^        ^
         *  |          |
         *  |          `- buf_ptr (in different buffer though!)
         *  `- s_code
         *
         * or
         *
         * "  unsigned int private:4\n"       C/C++, treat as bits.
         */
                
        if (parser_state_tos->in_decl)
        {
            if (!(((e_code - s_code > 6) &&
                   !strncmp (&buf_ptr[-8], "private:", 8)) &&
                  !isdigit (*buf_ptr)) &&
                !(((e_code - s_code > 8) &&
                   !strncmp (&buf_ptr[-10], "protected:", 10)) &&
                  !isdigit (*buf_ptr)) &&
                !(((e_code - s_code > 5) &&
                   !strncmp (&buf_ptr[-7], "public:", 7)) &&
                  !isdigit (*buf_ptr)))
            {
                *e_code++ = ':';
                parser_state_tos->want_blank = false;
                return;
            }
            else if (*s_code == ' ')
            {
                /*
                 * It is possible that dec_ind spaces have been inserted before
                 * the `public:' etc. label because indent thinks it's of the
                 * type:
                 */
                /*
                 * Only now we see the '4' isn't there.
                 * Remove those spaces:
                 */
                        
                char *p1 = s_code;
                char *p2 = s_code + *dec_ind;
                        
                while (p2 < e_code)
                {
                    *p1++ = *p2++;
                }
                        
                e_code -= *dec_ind;
                *e_code = '\0';
            }
        }
                
        parser_state_tos->in_stmt = false;      /* seeing a label does not
                                                 * imply we are in a stmt */
        for (t_ptr = s_code; *t_ptr; ++t_ptr)
        {
            *e_lab++ = *t_ptr;  /* turn everything so far into a label */
        }
                
        e_code = s_code;
        clear_buf_break_list ();        /* This is bullshit for C code, because
                                         * normally a label doesn't have breakpoints
                                         * at all of course.  But in the case of
                                         * wrong code, not clearing the list can make
                                         * indent core dump. */
        *e_lab++ = ':';
        set_buf_break (bb_label, paren_target);
        *e_lab++ = ' ';
        *e_lab = '\0';
                
        /* parser_state_tos->pcas e will be used by dump_line to decide
         * how to indent the label. force_nl will force a case n: to be
         * on a line by itself */
                
        *force_nl = parser_state_tos->pcase = *scase;
        *scase = false;
        parser_state_tos->want_blank = false;
    }
}

/******************************************************************************/
static void handle_token_doublecolon(void)
{
    *e_code++ = ':';
    *e_code++ = ':';
    parser_state_tos->want_blank = false;
    parser_state_tos->can_break = bb_doublecolon;
    parser_state_tos->last_u_d = true;
    parser_state_tos->saw_double_colon = true;
}

/******************************************************************************/
static void handle_token_semicolon(
   BOOLEAN        * scase,
   BOOLEAN        * force_nl,
   BOOLEAN        * sp_sw,
   int            * dec_ind,
   BOOLEAN        * last_token_ends_sp,
   exit_values_ty * file_exit_value)
{
    parser_state_tos->in_or_st = 0;
    parser_state_tos->saw_double_colon = false;
    *scase = false;
    squest = 0;

    /* The following code doesn't seem to do much good. Just because
     * we've found something like extern int foo();    or int (*foo)();
     * doesn't mean we are out of a declaration.  Now if it was serving
     * some purpose we'll have to address that.... if
     * (parser_state_tos->last_token == rparen)
     * parser_state_tos->in_parameter_declaration = 0; */

    parser_state_tos->cast_mask = 0;
    parser_state_tos->sizeof_mask = 0;
    parser_state_tos->block_init = 0;
    parser_state_tos->block_init_level = 0;
    parser_state_tos->just_saw_decl--;

    if (parser_state_tos->in_decl &&
        (s_code == e_code) && !buf_break_used &&
        !parser_state_tos->block_init)
    {
        while ((e_code - s_code) < (*dec_ind - 1))
        {
            check_code_size();
            set_buf_break (bb_dec_ind, paren_target);
            *e_code++ = ' ';
        }

        parser_state_tos->ind_stmt = false;
    }

    *e_code = '\0'; /* null terminate code sect */

    /* if we were in a first level structure declaration,
     * we aren't any more */

    parser_state_tos->in_decl = (parser_state_tos->dec_nest > 0) ? true : false;

    /* If we have a semicolon following an if, while, or for, and the
     * user wants us to, we should insert a space (to show that there
     * is a null statement there).  */

    if (*last_token_ends_sp && settings.space_sp_semicolon)
    {
        *e_code++ = ' ';
    }

    *e_code++ = ';';
    *e_code = '\0'; /* null terminate code sect */
    parser_state_tos->want_blank = true;

    /* we are no longer in the middle of a stmt */

    parser_state_tos->in_stmt = (parser_state_tos->p_l_follow > 0);

    if (!*sp_sw)
    {                       /* if not if for (;;) */
        do
        {
            if (parse (semicolon) != total_success)
            {
                *file_exit_value = indent_error;
            }
        } while(0);
                
        *force_nl = true;    /* force newline after a end of stmt */
    }
}

/******************************************************************************/
static void handle_token_lbrace(
   BOOLEAN        * force_nl,
   int            * dec_ind,
   exit_values_ty * file_exit_value)
{
    parser_state_tos->saw_double_colon = false;

    if (!parser_state_tos->block_init)
    {
        *force_nl = true;    /* force other stuff on same line as '{' onto
                              * new line */
        parser_state_tos->in_stmt = false;  /* dont indent the '{' */
    }
    else
    {
        /* dont indent the '{' unless it is followed by more code. */

        char *p = buf_ptr;

        for (;;)
        {
            p = skip_horiz_space(p);

            if (*p == EOL || (*p == '/' && p[1] == '/'))
            {
                parser_state_tos->in_stmt = false;
                break;
            }
            else if (*p == '/' && p[1] == '*')
            {
                p += 2;
                /* skip over comment */

                while (*p && *p != EOL && (*p != '*' || p[1] != '/'))
                {
                    ++p;
                }

                if (!*p || *p == EOL)
                {
                    parser_state_tos->in_stmt = false;
                    break;
                }
                p += 2;

                if (!*p)
                {
                    break;
                }
            }
            else
            {
                break;
            }

        }

        if (parser_state_tos->block_init_level <= 0)
        {
            parser_state_tos->block_init_level = 1;
        }
        else
        {
            parser_state_tos->block_init_level++;
        }
    }

    if (s_code != e_code && parser_state_tos->block_init != 1)
    {
        if ((!parser_state_tos->in_decl && !settings.btype_2) ||
            (parser_state_tos->in_decl &&
             !settings.braces_on_struct_decl_line &&
             !settings.braces_on_func_def_line))
        {
            dump_line (true, &paren_target);
            parser_state_tos->want_blank = false;
        }
        else
        {
            if (parser_state_tos->in_parameter_declaration &&
                !parser_state_tos->in_or_st)
            {
                parser_state_tos->i_l_follow = 0;
                
                if (!settings.braces_on_func_def_line)
                {
                    dump_line (true, &paren_target);
                }
                else
                {
                    *e_code++ = ' ';
                }
                
                parser_state_tos->want_blank = false;
            }
            else
            {
                parser_state_tos->want_blank = true;
            }
        }
    }

    if (parser_state_tos->in_parameter_declaration)
    {
        prefix_blankline_requested = 0;
    }

    if (s_code == e_code)
    {
        parser_state_tos->ind_stmt = false; /* dont put extra indentation
                                               on line with '{' */
    }

    if (parser_state_tos->in_decl && parser_state_tos->in_or_st)
    {
        /* This is a structure declaration.  */

        if (parser_state_tos->dec_nest >= di_stack_alloc)
        {
            di_stack_alloc *= 2;
            di_stack =
                    (int *) xrealloc ((char *) di_stack,
                                      di_stack_alloc * sizeof (*di_stack));
        }

        di_stack[parser_state_tos->dec_nest++] = *dec_ind;
    }
    else
    {
        parser_state_tos->in_decl = false;
        parser_state_tos->decl_on_line = false;     /* we cant be in the
                                                     * middle of a
                                                     * declaration, so dont
                                                     * do special
                                                     * indentation of
                                                     * comments */

        parser_state_tos->in_parameter_declaration = 0;
    }

    *dec_ind = 0;

    /* We are no longer looking for an initializer or structure. Needed
     * so that the '=' in "enum bar {a = 1" does not get interpreted as
     * the start of an initializer.  */

    parser_state_tos->in_or_st = 0;

    do
    {
        if (parse (lbrace) != total_success)
        {
            *file_exit_value = indent_error;
        }
    } while(0);
            
    set_buf_break (bb_lbrace, paren_target);
    if (parser_state_tos->want_blank && s_code != e_code)
    {
        /* put a blank before '{' if '{' is not at start of line */

        *e_code++ = ' ';
    }

    parser_state_tos->want_blank = false;
    *e_code++ = '{';
    *e_code = '\0'; /* null terminate code sect */

    parser_state_tos->just_saw_decl = 0;

    if (parser_state_tos->block_init &&
        (parser_state_tos->block_init_level >= 2))
    {
        /* Treat the indentation of the second '{' as a '('
         * in * struct foo { { bar }, ... } */

        if (++parser_state_tos->p_l_follow >=
            parser_state_tos->paren_indents_size)
        {
            parser_state_tos->paren_indents_size *= 2;
            parser_state_tos->paren_indents =
                    (short *) xrealloc ((char *) parser_state_tos->
                                        paren_indents,
                                        parser_state_tos->paren_indents_size *
                                        sizeof (short));
        }

        ++parser_state_tos->paren_depth;
        parser_state_tos->paren_indents[parser_state_tos->p_l_follow -
                                        1] = e_code - s_code;
    }
    else if (parser_state_tos->block_init &&
             (parser_state_tos->block_init_level == 1))
    {
        /* Put a blank after the first '{' */

        parser_state_tos->want_blank = true;
    }
}
/******************************************************************************/
static void handle_token_rbrace(
    BOOLEAN        * force_nl,
    int            * dec_ind,
    exit_values_ty * file_exit_value)
{
    /* semicolons can be omitted in declarations */
    if (((parser_state_tos->p_stack[parser_state_tos->tos] == decl) &&
         !parser_state_tos->block_init) ||
        /* ANSI C forbids label at end of compound statement, but we don't I guess :/ */
        (parser_state_tos->p_stack[parser_state_tos->tos] == casestmt))
    {
        if (parse (semicolon) != total_success)
        {
            *file_exit_value = indent_error;
        }
    }

    parser_state_tos->just_saw_decl = 0;
    parser_state_tos->ind_stmt = false;
    parser_state_tos->in_stmt  = false;

    if ((parser_state_tos->block_init_level-- == 1)
        && (s_code != e_code))
    {
        /* Found closing brace of declaration initialisation, with
         * code on the same line before the brace */

        if (parser_state_tos->matching_brace_on_same_line < 0)
        {
            /* The matching '{' is not on the same line:
             * put the '}' on its own line. */

            dump_line (true, &paren_target);
        }
        else
        {
            /* Put a space before the '}' */
            set_buf_break (bb_rbrace, paren_target);
            *e_code++ = ' ';
        }
    }

    *e_code++ = '}';
    parser_state_tos->want_blank = true;

    if (parser_state_tos->block_init &&
        (parser_state_tos->block_init_level > 0))
    {
        /* We were treating this { } as normal ( ) */

        --parser_state_tos->paren_depth;

        if (--parser_state_tos->p_l_follow < 0)
        {
            parser_state_tos->p_l_follow = 0;
            WARNING (_("Extra %c"),
                     (unsigned long) *((unsigned char *) token), 0);
        }
    }
    else if (parser_state_tos->dec_nest > 0)
    {
        /* we are in multi-level structure
         * declaration */

        *dec_ind = di_stack[--parser_state_tos->dec_nest];

        if ((parser_state_tos->dec_nest == 0) &&
            !parser_state_tos->in_parameter_declaration)
        {
            parser_state_tos->just_saw_decl = 2;
        }

        parser_state_tos->in_decl = true;
    }

    prefix_blankline_requested = 0;
            
    if (parse (rbrace) != total_success) 
    {
        *file_exit_value = indent_error;
    }
            
    parser_state_tos->search_brace =
            (settings.cuddle_else &&
             (parser_state_tos->p_stack[parser_state_tos->tos] == ifhead)) ||
            (settings.cuddle_do_while &&
             (parser_state_tos->p_stack[parser_state_tos->tos] == dohead));

    if (parser_state_tos->p_stack[parser_state_tos->tos] == stmtl)
    {
        if ( (parser_state_tos->last_rw != rw_struct_like) &&
             (parser_state_tos->last_rw != rw_enum) &&
             (parser_state_tos->last_rw != rw_decl) )
        {
            *force_nl = true;
        }
#if 0
        else if (!settings.braces_on_struct_decl_line &&
                 (parser_state_tos->block_init != 1))
        {
            *force_nl = true;
        }
#endif
    }

    if ( (parser_state_tos->p_stack[parser_state_tos->tos] == ifhead) ||
         ( (parser_state_tos->p_stack[parser_state_tos->tos] == dohead) &&
           !settings.cuddle_do_while && !settings.btype_2))
    {
        *force_nl = true;
    }

    if (!parser_state_tos->in_decl && (parser_state_tos->tos <= 0) &&
        settings.blanklines_after_procs && (parser_state_tos->dec_nest <= 0))
    {
        postfix_blankline_requested = 1;
        postfix_blankline_requested_code =
                parser_state_tos->in_decl ? decl : rbrace;
    }
}

/******************************************************************************/
static void handle_token_swstmt(
    BOOLEAN        * sp_sw,
    codes_ty       * hd_type)
{
            
    *sp_sw = true;
    *hd_type = swstmt;       /* keep this for when we have seen the
                              * expression */
    parser_state_tos->in_decl = false;
}

/******************************************************************************/
static void handle_token_sp_paren(
    BOOLEAN        * sp_sw,
    codes_ty       * hd_type)
{
    /* the interesting stuff is done after the expression is scanned */
    *sp_sw = true;

    /* remember the type of header for later use by parser */
    *hd_type =
            (*token == 'i' ? ifstmt : (*token == 'w' ? whilestmt : forstmt));
}

/******************************************************************************/
static void handle_token_nparen(
    BOOLEAN        * force_nl,
    exit_values_ty * file_exit_value,
    BOOLEAN        * last_else)
{
    parser_state_tos->in_stmt = false;
    if (*token == 'e')
    {
        if (e_code != s_code && (!settings.cuddle_else || e_code[-1] != '}'))
        {
            if (settings.verbose)
            {
                WARNING (_("Line broken"), 0, 0);
            }
            
            dump_line (true, &paren_target);       /* make sure this starts a line */
            parser_state_tos->want_blank = false;
        }
        
        /* This will be over ridden when next we read an `if' */
        
        *force_nl = true;    /* also, following stuff must go onto new
                              * line */
        *last_else = 1;

        if (parse (elselit) != total_success) 
        {
            *file_exit_value = indent_error;
        }
    }
    else
    {
        if (e_code != s_code)
        {
            /* make sure this starts a line */
            
            if (settings.verbose)
            {
                WARNING (_("Line broken"), 0, 0);
            }
            
            dump_line (true, &paren_target);
            parser_state_tos->want_blank = false;
        }
        
        *force_nl = true;    /* also, following stuff must go onto new
                              * line */
        *last_else = 0;

        if (parse (dolit) != total_success) 
        {
            *file_exit_value = indent_error;
        }
    }
}

/******************************************************************************/
static void handle_token_overloaded(
    const bb_code_ty can_break)
{
    char           * t_ptr;

    if (parser_state_tos->want_blank)
    {
        set_buf_break (bb_overloaded, paren_target);
        *e_code++ = ' ';
    }
    else if (can_break)
    {
        set_buf_break (can_break, paren_target);
    }

    parser_state_tos->want_blank = true;

    for (t_ptr = token; t_ptr < token_end; ++t_ptr)
    {
        check_code_size();
        *e_code++ = *t_ptr;
    }

    *e_code = '\0'; /* null terminate code sect */
}

/******************************************************************************/
static void handle_token_decl(
    int            * dec_ind,
    exit_values_ty * file_exit_value)
{
    /* handle C++ const function declarations like
     * const MediaDomainList PVR::get_itsMediaDomainList() const
     * {
     * return itsMediaDomainList;
     * }
     * by ignoring "const" just after a parameter list */

    if ((parser_state_tos->last_token == rparen) &&
        parser_state_tos->in_parameter_declaration &&
        parser_state_tos->saw_double_colon &&
        !strncmp (token, "const", 5))
    {
        char           * t_ptr;
        set_buf_break (bb_const_qualifier, paren_target);
        *e_code++ = ' ';

        for (t_ptr = token; t_ptr < token_end; ++t_ptr)
        {
            check_code_size();
            *e_code++ = *t_ptr;
        }

        *e_code = '\0';     /* null terminate code sect */
    }
    else
    {
        
        if (!parser_state_tos->sizeof_mask)
        {
            if (parse (decl) != total_success)
            {
                *file_exit_value = indent_error;
            }
        }
        
        if ((parser_state_tos->last_token == rparen) &&
            (parser_state_tos->tos <= 1))
        {
            parser_state_tos->in_parameter_declaration = 1;
            
            if (s_code != e_code)
            {
                dump_line (true, &paren_target);
                parser_state_tos->want_blank = false;
            }
        }

        if (parser_state_tos->in_parameter_declaration &&
            (parser_state_tos->dec_nest == 0) &&
            (parser_state_tos->p_l_follow == 0))
        {
            parser_state_tos->ind_level = parser_state_tos->i_l_follow =
                    settings.indent_parameters;

            parser_state_tos->ind_stmt = false;
        }
        
        /* in_or_st set for struct or initialization decl. Don't set it if
         * we're in ansi prototype */
        
        if (!parser_state_tos->paren_depth)
        {
            parser_state_tos->in_or_st = 1;
        }
        
        if (!parser_state_tos->sizeof_mask)
        {
            parser_state_tos->in_decl      = true;
            parser_state_tos->decl_on_line = true;
            
            if (parser_state_tos->dec_nest <= 0)
            {
                parser_state_tos->just_saw_decl = 2;
            }
        }
        
        if (prefix_blankline_requested &&
            ((parser_state_tos->block_init != 0) ||
             (parser_state_tos->block_init_level != -1) ||
             (parser_state_tos->last_token != rbrace) ||
             (e_code != s_code) || 
             (e_lab  != s_lab)  || 
             (e_com  != s_com)))
        {
            prefix_blankline_requested = 0;
        }
        
        *dec_ind = settings.decl_indent > 0 ? settings.decl_indent :
                                              token_end - token + 1; /* get length of token plus 1 */
    }
}

/******************************************************************************/
static void handle_token_ident(
    BOOLEAN        * force_nl,
    BOOLEAN        * sp_sw,
    codes_ty       * hd_type,
    int            * dec_ind,
    exit_values_ty * file_exit_value,
    const bb_code_ty can_break,
    BOOLEAN          is_procname_definition)
{
    /* If we are in a declaration, we must indent identifier. But not
     * inside the parentheses of an ANSI function declaration.  */

    if (parser_state_tos->in_decl &&
        (parser_state_tos->p_l_follow == 0) &&
        (parser_state_tos->last_token != rbrace))
    {
        if (parser_state_tos->want_blank)
        {
            set_buf_break (bb_ident, paren_target);
            *e_code++ = ' ';
            *e_code = '\0'; /* null terminate code sect */
        }
        else if (can_break)
        {
            set_buf_break (can_break, paren_target);
        }

        parser_state_tos->want_blank = false;

        if ((is_procname_definition == false) ||
            (!settings.procnames_start_line && (s_code != e_code)))
        {
            if (!parser_state_tos->block_init && !buf_break_used)
            {
                if (is_procname_definition)
                {
                    *dec_ind = 0;
                }

                while ((e_code - s_code) < *dec_ind)
                {
                    check_code_size();
                    set_buf_break (bb_dec_ind, paren_target);
                    *e_code++ = ' ';
                }

                *e_code = '\0';     /* null terminate code sect */
                parser_state_tos->ind_stmt = false;
            }
        }
        else
        {
            if ((s_code != e_code) &&
                (parser_state_tos->last_token != doublecolon))
            {
                dump_line(true, &paren_target);
            }

            *dec_ind = 0;
            parser_state_tos->want_blank = false;
        }
    }
    else if (*sp_sw && parser_state_tos->p_l_follow == 0)
    {
        *sp_sw = false;
        *force_nl = true;
        parser_state_tos->last_u_d = true;
        parser_state_tos->in_stmt = false;
                
        if (parse (*hd_type) != total_success) 
        {
            *file_exit_value = indent_error;
        }
    }
}

/******************************************************************************/

static void handle_token_struct_delim(void)
{
    char           * t_ptr;
    for (t_ptr = token; t_ptr < token_end; ++t_ptr)
    {
        check_code_size();
        *e_code++ = *t_ptr;
    }

    parser_state_tos->want_blank = false;   /* dont put a blank after a
                                             * period */
    parser_state_tos->can_break = bb_struct_delim;
}

/******************************************************************************/
static void handle_token_comma(
    BOOLEAN        * force_nl,
    int            * dec_ind,
    BOOLEAN          is_procname_definition)
{
    parser_state_tos->want_blank = true;

    if ((parser_state_tos->paren_depth == 0) &&
        parser_state_tos->in_decl &&
        !buf_break_used && (is_procname_definition == false) &&
        !parser_state_tos->block_init)
    {
        while ((e_code - s_code) < (*dec_ind - 1))
        {
            check_code_size();
            set_buf_break (bb_dec_ind, paren_target);
            *e_code++ = ' ';
        }

        parser_state_tos->ind_stmt = false;
    }

    *e_code++ = ',';

    if (parser_state_tos->p_l_follow == 0)
    {
        if (parser_state_tos->block_init_level <= 0)
        {
            parser_state_tos->block_init = 0;
        }

        /* If we are in a declaration, and either the user wants all
         * comma'd declarations broken, or the line is getting too
         * long, break the line.  */

        if (break_comma && !settings.leave_comma)
        {
            *force_nl = true;
        }
    }

    if (parser_state_tos->block_init)
    {
        parser_state_tos->in_stmt = false;  /* Don't indent after comma */
    }

    /* For declarations, if user wants all fn decls broken, force that
     * now. */

    if (settings.break_function_decl_args &&
        (!parser_state_tos->in_or_st &&
         parser_state_tos->in_stmt && parser_state_tos->in_decl))
    {
        *force_nl = true;
    }

}

/******************************************************************************/
static void handle_token_preesc(
    exit_values_ty * file_exit_value)
{
    char * t_ptr;
    char * p;

    if ((s_com != e_com) || (s_lab != e_lab) || (s_code != e_code))
    {
        dump_line(true, &paren_target);
    }

    {
        int in_comment = 0;
        int in_cplus_comment = 0;
        int com_start = 0;
        char quote = 0;
        int com_end = 0;

        /* ANSI allows spaces between '#' and preprocessor directives.
         * If the user specified "-lps" and there are such spaces,
         * they will be part of `token', otherwise `token' is just
         * '#'. */

        for (t_ptr = token; t_ptr < token_end; ++t_ptr)
        {
            check_lab_size();
            *e_lab++ = *t_ptr;
        }

        while (!had_eof && (*buf_ptr != EOL || in_comment))
        {
            check_lab_size();
            *e_lab = *buf_ptr++;

            if (buf_ptr >= buf_end)
            {
                fill_buffer ();
            }

            switch (*e_lab++)
            {
            case BACKSLASH:
                if (!in_comment && !in_cplus_comment)
                {
                    *e_lab++ = *buf_ptr++;
                    if (buf_ptr >= buf_end)
                    {
                        fill_buffer ();
                    }
                }
                break;

            case '/':
                if (((*buf_ptr == '*') ||
                     (*buf_ptr == '/')) &&
                    !in_comment && !in_cplus_comment && !quote)
                {
                    save_com.column = current_column () - 1;

                    if (*buf_ptr == '/')
                    {
                        in_cplus_comment = 1;
                    }
                    else
                    {
                        in_comment = 1;
                    }

                    *e_lab++ = *buf_ptr++;
                    com_start = e_lab - s_lab - 2;

                    /* Store the column that corresponds with the start
                     * of the buffer */

                    if (save_com.ptr == save_com.end)
                    {
                        save_com.start_column = current_column () - 2;
                    }
                }
                break;

            case '"':
            case '\'':
                if (!quote)
                {
                    quote = e_lab[-1];
                }
                else if (e_lab[-1] == quote)
                {
                    quote = 0;
                }

                break;

            case '*':
                if (*buf_ptr == '/' && in_comment)
                {
                    in_comment = 0;
                    *e_lab++ = *buf_ptr++;
                    com_end = e_lab - s_lab;
                }
                break;
            }
        }

        while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == TAB))
        {
            e_lab--;
        }


        if (in_cplus_comment)   /* Should we also check in_comment? -jla */
        {
            in_cplus_comment = 0;
            *e_lab++ = *buf_ptr++;
            com_end = e_lab - s_lab;
        }

        if (e_lab - s_lab == com_end && bp_save == 0)
        {
            /* comment on preprocessor line */

            if (save_com.end != save_com.ptr)
            {
                need_chars (&save_com, 2);
                *save_com.end++ = EOL;  /* add newline between
                                         * comments */
                *save_com.end++ = ' ';
                save_com.len += 2;
                --line_no;
            }

            need_chars (&save_com, com_end - com_start + 1);
            strncpy (save_com.end, s_lab + com_start,
                     com_end - com_start);
            save_com.end[com_end - com_start] = '\0';
            save_com.end += com_end - com_start;
            save_com.len += com_end - com_start;

            e_lab = s_lab + com_start;

            while ((e_lab > s_lab) &&
                   ((e_lab[-1] == ' ') || (e_lab[-1] == TAB)))
            {
                e_lab--;
            }


            /* Switch input buffers so that calls to lexi() will
             * read from our save buffer. */

            bp_save = buf_ptr;
            be_save = buf_end;
            buf_ptr = save_com.ptr;
            need_chars (&save_com, 1);
            buf_end = save_com.end;
            save_com.end = save_com.ptr;        /* make save_com empty */
        }

        *e_lab = '\0';  /* null terminate line */
        parser_state_tos->pcase = false;
    }

    p = s_lab + 1;

    p = skip_horiz_space(p);

    if (strncmp (p, "if", 2) == 0)
    {
        if (settings.blanklines_around_conditional_compilation)
        {
            prefix_blankline_requested++;
            prefix_blankline_requested_code = preesc;

            while (*in_prog_pos++ == EOL)
            {
            }

            in_prog_pos--;
        }

        {
            /* Push a copy of the parser_state onto the stack. All
             * manipulations will use the copy at the top of stack, and
             * then we can return to the previous state by popping the
             * stack.  */

            parser_state_ty *new;

            new = (parser_state_ty *)
                    xmalloc (sizeof (parser_state_ty));
            (void) memcpy (new, parser_state_tos,
                           sizeof (parser_state_ty));

            /* We need to copy the dynamically allocated arrays in the
             * struct parser_state too.  */

            new->p_stack =
                    (codes_ty *) xmalloc (parser_state_tos->p_stack_size *
                                          sizeof (codes_ty));

            (void) memcpy (new->p_stack, parser_state_tos->p_stack,
                           (parser_state_tos->p_stack_size *
                            sizeof (codes_ty)));

            new->il =
                    (int *) xmalloc (parser_state_tos->p_stack_size *
                                     sizeof (int));

            (void) memcpy (new->il, parser_state_tos->il,
                           parser_state_tos->p_stack_size *
                           sizeof (int));

            new->cstk =
                    (int *) xmalloc (parser_state_tos->p_stack_size *
                                     sizeof (int));

            (void) memcpy (new->cstk, parser_state_tos->cstk,
                           parser_state_tos->p_stack_size *
                           sizeof (int));

            new->paren_indents =
                    (short *) xmalloc (parser_state_tos->paren_indents_size *
                                       sizeof (short));
            (void) memcpy (new->paren_indents,
                           parser_state_tos->paren_indents,
                           (parser_state_tos->paren_indents_size *
                            sizeof (short)));

            new->next = parser_state_tos;
            parser_state_tos = new;
            /* GDB_HOOK_parser_state_tos */
        }
    }
    else if ((strncmp (p, "else", 4) == 0) ||
             (strncmp (p, "elif", 4) == 0))
    {
        /* When we get #else, we want to restore the parser state to
         * what it was before the matching #if, so that things get
         * lined up with the code before the #if.  However, we do not
         * want to pop the stack; we just want to copy the second to
         * top elt of the stack because when we encounter the #endif,
         * it will pop the stack.  */

        else_or_endif = (strncmp (p, "else", 4) == 0);
        prefix_blankline_requested = 0;

        if (parser_state_tos->next)
        {
            /* First save the addresses of the arrays for the top of
             * stack.  */

            codes_ty * tos_p_stack       = parser_state_tos->p_stack;
            int      * tos_il            = parser_state_tos->il;
            int      * tos_cstk          = parser_state_tos->cstk;
            short    * tos_paren_indents =
                    parser_state_tos->paren_indents;
            parser_state_ty * second = parser_state_tos->next;

            (void) memcpy (parser_state_tos, second,
                           sizeof (parser_state_ty));
            parser_state_tos->next = second;

            /* Now copy the arrays from the second to top of stack to
             * the top of stack.  */

            /* Since the p_stack, etc. arrays only grow, never shrink,
             * we know that they will be big enough to fit the array
             * from the second to top of stack.  */

            parser_state_tos->p_stack = tos_p_stack;
            (void) memcpy (parser_state_tos->p_stack,
                           parser_state_tos->next->p_stack,
                           parser_state_tos->p_stack_size *
                           sizeof (codes_ty));

            parser_state_tos->il = tos_il;
            (void) memcpy (parser_state_tos->il,
                           parser_state_tos->next->il,
                           (parser_state_tos->p_stack_size *
                            sizeof (int)));

            parser_state_tos->cstk = tos_cstk;
            (void) memcpy (parser_state_tos->cstk,
                           parser_state_tos->next->cstk,
                           (parser_state_tos->p_stack_size *
                            sizeof (int)));

            parser_state_tos->paren_indents = tos_paren_indents;
            (void) memcpy (parser_state_tos->paren_indents,
                           parser_state_tos->next->paren_indents,
                           (parser_state_tos->paren_indents_size *
                            sizeof (short)));
        }
        else
        {
            ERROR (else_or_endif ? _("Unmatched #else") :
                   _("Unmatched #elif"), 0, 0);
            *file_exit_value = indent_error;
        }
    }
    else if (strncmp (p, "endif", 5) == 0)
    {
        else_or_endif = true;
        prefix_blankline_requested = 0;
        /* We want to remove the second to top elt on the stack, which
         * was put there by #if and was used to restore the stack at
         * the #else (if there was one). We want to leave the top of
         * stack unmolested so that the state which we have been using
         * is unchanged.  */

        if (parser_state_tos->next)
        {
            parser_state_ty *second = parser_state_tos->next;

            parser_state_tos->next = second->next;
            free (second->p_stack);
            free (second->il);
            free (second->cstk);
            free (second->paren_indents);
            free (second);
        }
        else
        {
            ERROR (_("Unmatched #endif"), 0, 0);
            *file_exit_value = indent_error;
        }

        if (settings.blanklines_around_conditional_compilation)
        {
            postfix_blankline_requested++;
            postfix_blankline_requested_code = preesc;
            n_real_blanklines = 0;
        }
    }

    /* Don't put a blank line after declarations if they are directly
     * followed by an #else or #endif -Run */

    if (else_or_endif && prefix_blankline_requested_code == decl)
    {
        prefix_blankline_requested = 0;
    }

    /* Normally, subsequent processing of the newline character
     * causes the line to be printed.  The following clause handles
     * a special case (comma-separated declarations separated
     * by the preprocessor lines) where this doesn't happen. */

    if ((parser_state_tos->last_token == comma) &&
        (parser_state_tos->p_l_follow <= 0) &&
        settings.leave_comma &&
        !parser_state_tos->block_init &&
        break_comma && (s_com == e_com))
    {
        dump_line(true, &paren_target);
        parser_state_tos->want_blank = false;
    }

}

/******************************************************************************/
static void handle_token_comment(
    BOOLEAN        * force_nl,
    BOOLEAN        * flushed_nl)
{
            if (parser_state_tos->last_saw_nl && (s_code != e_code))
            {
                *flushed_nl = false;
                dump_line(true, &paren_target);
                parser_state_tos->want_blank = false;
                *force_nl = false;
            }
            print_comment (&paren_target);
}

/******************************************************************************/
static void handle_token_attribute(
    )
{
    char           * t_ptr;
    
    if (s_code != e_code)
    {
        set_buf_break (bb_attribute, paren_target);
        *e_code++ = ' ';
    }

    for (t_ptr = token; t_ptr < token_end; ++t_ptr)
    {
        check_code_size();
        *e_code++ = *t_ptr;
    }

    parser_state_tos->in_decl = false;
    parser_state_tos->want_blank = true;
}

/******************************************************************************/
static void handle_the_token(
    const codes_ty   type_code,
    BOOLEAN        * scase,
    BOOLEAN        * force_nl,
    BOOLEAN        * sp_sw,
    BOOLEAN        * flushed_nl,
    codes_ty       * hd_type,
    int            * dec_ind,
    BOOLEAN        * last_token_ends_sp,
    exit_values_ty * file_exit_value,
    const bb_code_ty can_break,
    BOOLEAN        * last_else,
    BOOLEAN          is_procname_definition)
{
    switch (type_code)
    {
        case form_feed:     /* found a form feed in line */
            handle_token_form_feed();
            break;

        case newline:
            handle_token_newline(force_nl);
            break;

        case lparen:
            handle_token_lparen(force_nl, sp_sw, dec_ind);
            break;

        case rparen:
            handle_token_rparen(force_nl, sp_sw, hd_type, last_token_ends_sp,
                                file_exit_value);
            break;

        case unary_op:
            /* this could be any unary operation */
            handle_token_unary_op( dec_ind, can_break);
            break;

        case binary_op:
            /* any binary operation */
            handle_token_binary_op(can_break);
            break;

        case postop:
            /* got a trailing ++ or -- */
            handle_token_postop();
            break;

        case question:
            /* got a ? */
            handle_token_question(can_break);
            break;

        case casestmt:
            /* got word 'case' or 'default' */
            handle_token_casestmt(scase, file_exit_value);
            copy_id(type_code, force_nl, file_exit_value,can_break);
            break;
            
        case colon:
            /* got a ':' */
            handle_token_colon(scase, force_nl, dec_ind, can_break);
            break;

        case doublecolon:
            /* Deal with C++ Class::Method */
            handle_token_doublecolon();
            break;

        case semicolon:
            /* we are not in an initialization or structure declaration */
            handle_token_semicolon(scase, force_nl, sp_sw, dec_ind,
                                   last_token_ends_sp, file_exit_value);
            break;

        case lbrace:
            /* got a '{' */
            handle_token_lbrace(force_nl, dec_ind, file_exit_value);
            break;

        case rbrace:
            /* got a '}' */
            handle_token_rbrace(force_nl, dec_ind, file_exit_value);
            
            break;

        case swstmt:
            /* got keyword "switch" */
            handle_token_swstmt(sp_sw, hd_type);
            copy_id(type_code, force_nl, file_exit_value, can_break);
            break;
            
        case sp_paren:
            /* token is if, while, for */
            handle_token_sp_paren(sp_sw,  hd_type);
            copy_id(type_code, force_nl, file_exit_value, can_break);
            break;
            
        case sp_else:
            /* got else */
        case sp_nparen:
            /* got do */
            handle_token_nparen(force_nl, file_exit_value, last_else);
            copy_id(type_code, force_nl, file_exit_value,can_break);
            break;
            
        case overloaded:
            /* Handle C++ operator overloading like:
             *
             * Class foo::operator = ()"
             *
             * This is just like a decl, but we need to remember this
             * token type. */
            
            handle_token_overloaded(can_break);
            break;

        case decl:
            /* we have a declaration type (int, register, etc.) */

            handle_token_decl(dec_ind, file_exit_value);
            
            copy_id(type_code, force_nl, file_exit_value, can_break);
            break;
            
        case cpp_operator:
            /* Handle C++ operator overloading.  See case overloaded above. */
        case ident:
            /* got an identifier or constant */
            handle_token_ident(force_nl,  sp_sw, hd_type,
                               dec_ind, file_exit_value,
                               can_break, is_procname_definition);
            
            copy_id(type_code, force_nl, file_exit_value, can_break);
            
            break;

        case struct_delim:
            handle_token_struct_delim();
            break;

        case comma:
            handle_token_comma(force_nl, dec_ind, is_procname_definition);
            break;

        case preesc:
            /* got the character '#' */
            handle_token_preesc(file_exit_value);
            break;

        case comment:
        case cplus_comment:
            /* A C or C++ comment. */
            handle_token_comment(force_nl, flushed_nl);
            break;

            /* An __attribute__ qualifier */
        case attribute:
            handle_token_attribute();
            break;

        default:
            abort ();
    }                       /* end of big switch stmt */
}

/******************************************************************************/
static void sw_buffer(void)
{
    parser_state_tos->search_brace = false;
    bp_save = buf_ptr;
    be_save = buf_end;
    buf_ptr = save_com.ptr;
    need_chars (&save_com, 1);
    buf_end = save_com.end;
    save_com.end = save_com.ptr;        /* make save_com empty */
}

/******************************************************************************/
static BOOLEAN search_brace(
    codes_ty       * type_code,
    BOOLEAN        * force_nl,
    BOOLEAN        * flushed_nl,
    BOOLEAN        * last_else,
    BOOLEAN        * is_procname_definition)
{
    while (parser_state_tos->search_brace)
    {
        /* After scanning an if(), while (), etc., it might be necessary to
         * keep track of the text between the if() and the start of the
         * statement which follows.  Use save_com to do so.
         */

        switch (*type_code)
        {
        case newline:
            ++line_no;
            *flushed_nl = true;
            break;
        case form_feed:
            break;              /* form feeds and newlines found here will be
                                 * ignored */
        case lbrace:
            /* Ignore buffering if no comment stored. */

            if (save_com.end == save_com.ptr)
            {
                parser_state_tos->search_brace = false;
                return true;                                                            /* RETURN */
            }

            /* We need to put the '{' back into save_com somewhere.  */

            if (settings.btype_2 && (parser_state_tos->last_token != rbrace))
            {
                /* Kludge to get my newline back */
                if ((parser_state_tos->last_token == sp_else) &&
                    (save_com.end > &save_com.ptr[4]) &&
                    (save_com.end[-2] == '*') &&
                    (save_com.end[-1] == '/') &&
                    (save_com.ptr[2] == '/') &&
                    (save_com.ptr[3] == '*'))
                {
                    char *p;

                    for (p = &save_com.ptr[4];
                         *p != '\n' && p < &save_com.end[-2]; ++p)
                    {
                    }

                    if (*p != '\n')
                    {
                        *save_com.end++ = EOL;
                    }
                }

                /* Put the brace at the beginning of the saved buffer */

                save_com.ptr[0] = '{';
                save_com.len = 1;
                save_com.column = current_column ();
            }
            else
            {
                /* Put the brace at the end of the saved buffer, after
                 * a newline character.  The newline char will cause
                 * a `dump_line' call, thus ensuring that the brace
                 * will go into the right column. */

                *save_com.end++ = EOL;
                *save_com.end++ = '{';
                save_com.len += 2;
            }

            /* Go to common code to get out of this loop.  */

            sw_buffer();
            break;
                    
        case comment:
            /* Save this comment in the `save_com' buffer, for
             * possible re-insertion in the output stream later. */

            if (!*flushed_nl || (save_com.end != save_com.ptr))
            {
                need_chars (&save_com, 10);

                if (save_com.end == save_com.ptr)
                {
                    /* if this is the first comment, we must set
                     * up the buffer */

                    save_com.start_column = current_column ();
                    save_com.ptr[0] = save_com.ptr[1] = ' ';
                    save_com.end = save_com.ptr + 2;
                    save_com.len = 2;
                    save_com.column = current_column ();
                }
                else
                {
                    *save_com.end++ = EOL;      /* add newline between
                                                 * comments */
                    *save_com.end++ = ' ';
                    save_com.len += 2;
                    --line_no;
                }

                *save_com.end++ = '/';  /* copy in start of comment */
                *save_com.end++ = '*';

                for (;;)
                {
                    /* loop until we get to the end of the
                     * comment */

                    /* make sure there is room for this character and
                     * (while we're at it) the '/' we might add at the end
                     * of the loop. */
                        
                    need_chars (&save_com, 2);
                    *save_com.end = *buf_ptr++;
                    save_com.len++;

                    if (buf_ptr >= buf_end)
                    {
                        fill_buffer ();

                        if (had_eof)
                        {
                            ERROR (_("EOF encountered in comment"), 0, 0);
                            return indent_punt;                               /* RETURN */
                        }
                    }

                    if (*save_com.end++ == '*' && *buf_ptr == '/')
                    {
                        break;  /* we are at end of comment */
                    }
                }

                *save_com.end++ = '/';  /* add ending slash */
                save_com.len++;

                if (++buf_ptr >= buf_end)       /* get past / in buffer */
                {
                    fill_buffer ();
                }

                break;
            }

            /* Just some statement. */

        default:
            /* Some statement.  Unless it's special, arrange
             * to break the line. */

            if (((*type_code == sp_paren) && (*token == 'i') &&    /* "if" statement */
                 *last_else) ||
                ((*type_code == sp_else)  &&     /* "else" statement */
                 (e_code != s_code) && (e_code[-1] == '}')))       /* The "else" follows '}' */
            {
                *force_nl = false;
            }
            else if (*flushed_nl)
            {
                *force_nl = true;
            }

            if (save_com.end == save_com.ptr)
            {
                /* ignore buffering if comment wasnt saved up */

                parser_state_tos->search_brace = false;
                return true;                                      /* RETURN */
            }

            if (*force_nl)
            {
                *force_nl = false;
                --line_no;      /* this will be re-increased when the nl is read from the buffer */
                need_chars (&save_com, 2);
                *save_com.end++ = EOL;
                save_com.len++;
                if (settings.verbose && !*flushed_nl)
                {
                    WARNING (_("Line broken"), 0, 0);
                }

                *flushed_nl = false;
            }

            /* Now copy this token we just found into the saved buffer. */

            *save_com.end++ = ' ';
            save_com.len++;
            buf_ptr = token;

            /* A total nightmare is created by trying to get the
             * next token into this save buffer.  Rather than that,
             * I've just backed up the buffer pointer to point
             * at `token'. --jla 9/95 */

            parser_state_tos->procname      = "\0";
            parser_state_tos->procname_end  = "\0";
            parser_state_tos->classname     = "\0";
            parser_state_tos->classname_end = "\0";

            /* Switch input buffers so that calls to lexi() will
             * read from our save buffer. */

            sw_buffer();
            break;
        }                   /* end of switch */

        if (*type_code != code_eof)
        {
            int just_saw_nl = false;

            if (*type_code == newline)
            {
                just_saw_nl = true;
            }

            *type_code = lexi ();

            if ( ( (*type_code == newline) && (just_saw_nl == true)) ||
                 ( (*type_code == comment) && parser_state_tos->last_saw_nl &&
                   (parser_state_tos->last_token != sp_else)))
            {
                dump_line(true, &paren_target);
                *flushed_nl = true;
            }

            *is_procname_definition = ((parser_state_tos->procname[0] != '\0') &&
                                       parser_state_tos->in_parameter_declaration);
        }

        if ((*type_code == ident) && *flushed_nl &&
            !settings.procnames_start_line &&
            parser_state_tos->in_decl &&
            (parser_state_tos->procname[0] != '\0'))
        {
            *flushed_nl = 0;
        }
    }                       /* end of while (search_brace) */

    *last_else = 0;

    return true;
}

/******************************************************************************/
static exit_values_ty indent_main_loop(void)
{
    codes_ty         hd_type         = code_eof;
    char           * t_ptr           = NULL;
    codes_ty         type_code       = start_token;
    exit_values_ty   file_exit_value = total_success;
    int              dec_ind         = 0; /* current indentation for declarations */

    BOOLEAN          scase           = false; /* true when we've just see a "case";
                                               * determines what to do with the
                                               * following colon */
    BOOLEAN          flushed_nl;              /* Used when buffering up comments to remember that
                                               * a newline was passed over */
    BOOLEAN          sp_sw           = false; /* true when in the expression part of if(...),
                                               * while(...), etc. */
    BOOLEAN          force_nl        = false;

    /* last_token_ends_sp: True if we have just encountered the end of an if (...),
     * etc. (i.e. the ')' of the if (...) was the last token).  The variable is
     * set to 2 in the middle of the main token reading loop and is decremented
     * at the beginning of the loop, so it will reach zero when the second token
     * after the ')' is read.
     */

    BOOLEAN          last_token_ends_sp = false;

    BOOLEAN          last_else = false; /* true if last keyword was an else */

    for (;;)
    {
        /* this is the main loop.  it will go until
         * we reach eof */

        BOOLEAN is_procname_definition;
        bb_code_ty can_break;

        if (type_code != newline)
        {
            can_break = parser_state_tos->can_break;
        }

        parser_state_tos->last_saw_nl = false;
        parser_state_tos->can_break = bb_none;

        type_code = lexi ();    /* lexi reads one token.  "token" points to
                                 * the actual characters. lexi returns a code
                                 * indicating the type of token */

        /* If the last time around we output an identifier or
         * a paren, then consider breaking the line here if it's
         * too long.
         *
         * A similar check is performed at the end of the loop, after
         * we've put the token on the line. */

        if ((settings.max_col > 0) &&
            (buf_break != NULL) &&
            ( ( (parser_state_tos->last_token == ident) &&
                (type_code != comma) &&
                (type_code != semicolon) &&
                (type_code != newline) &&
                (type_code != form_feed) &&
                (type_code != rparen) &&
                (type_code != struct_delim)) ||
              ( (parser_state_tos->last_token == rparen) &&
                (type_code != comma) &&
                (type_code != rparen) ) ) &&
            (output_line_length () > settings.max_col))
        {
            break_line = 1;
        }

        if (last_token_ends_sp > 0)
        {
            last_token_ends_sp--;
        }

        is_procname_definition =
                (((parser_state_tos->procname[0] != '\0') &&
                  parser_state_tos->in_parameter_declaration) ||
                 (parser_state_tos->classname[0] != '\0'));

        /* The following code moves everything following an if (), while (),
         * else, etc. up to the start of the following stmt to a buffer. This
         * allows proper handling of both kinds of brace placement.
         */

        flushed_nl = false;

        if (!search_brace(&type_code, &force_nl, &flushed_nl, &last_else, &is_procname_definition))
        {
            /* Hit EOF unexpectedly in comment. */
            return indent_punt;
        }
        
        if (type_code == code_eof)
        {
            /* we got eof */
            if (s_lab != e_lab || s_code != e_code || s_com != e_com)   /* must dump end of line */
            {
                dump_line(true, &paren_target);
            }

            if (parser_state_tos->tos > 1)      /* check for balanced braces */
            {
                ERROR (_("Unexpected end of file"), 0, 0);
                file_exit_value = indent_error;
            }

            if (settings.verbose)
            {
                printf (_("There were %d non-blank output lines and %d comments\n"),
                        (int) out_lines, (int) com_lines);
                if (com_lines > 0 && code_lines > 0)
                {
                    printf (_("(Lines with comments)/(Lines with code): %6.3f\n"),
                            (1.0 * com_lines) / code_lines);
                }
            }
            flush_output ();

            return file_exit_value;                                              /* RETURN */
        }

        if ((type_code != comment) &&
            (type_code != cplus_comment) &&
            (type_code != newline) &&
            (type_code != preesc) &&
            (type_code != form_feed))
        {
            if (force_nl &&
                (type_code != semicolon) &&
                ( (type_code != lbrace) ||
                  (!parser_state_tos->in_decl && !settings.btype_2) ||
                  (parser_state_tos->in_decl && !settings.braces_on_struct_decl_line) ||
                  (parser_state_tos->last_token == rbrace)))
            {
                if (settings.verbose && !flushed_nl)
                {
                    WARNING (_("Line broken 2"), 0, 0);
                }

                flushed_nl = false;
                dump_line(true, &paren_target);
                parser_state_tos->want_blank = false;
                force_nl = false;
            }

            parser_state_tos->in_stmt = true;   /* turn on flag which causes
                                                 * an extra level of
                                                 * indentation. this is
                                                 * turned off by a ; or } */
            if (s_com != e_com)
            {
                /* the code has an embedded comment in the
                 * line. Move it from the com buffer to the
                 * code buffer.
                 *
                 * Do not add a space before the comment if it is the first
                 * thing on the line.
                 */

                if (e_code != s_code)
                {
                    set_buf_break (bb_embedded_comment_start, paren_target);
                    *e_code++ = ' ';
                    embedded_comment_on_line = 2;
                }
                else
                {
                    embedded_comment_on_line = 1;
                }

                for (t_ptr = s_com; *t_ptr; ++t_ptr)
                {
                    check_code_size();
                    *e_code++ = *t_ptr;
                }

                set_buf_break (bb_embedded_comment_end, paren_target);
                *e_code++ = ' ';
                *e_code = '\0'; /* null terminate code sect */
                parser_state_tos->want_blank = false;
                e_com = s_com;
            }
        }
        else if ((type_code != comment) &&
                 (type_code != cplus_comment) &&
                 !(settings.break_function_decl_args &&
                   (parser_state_tos->last_token == comma)) &&
                 !( (parser_state_tos->last_token == comma) &&
                    !settings.leave_comma))
        {
            /* preserve force_nl thru a comment but
             * cancel forced newline after newline, form feed, etc.
             * however, don't cancel if last thing seen was comma-newline
             * and -bc flag is on. */

            force_nl = false;
        }

        /* Main switch on type of token scanned */

        check_code_size();
        
        /* now, decide what to do with the token */

        handle_the_token(type_code, &scase, &force_nl, &sp_sw, &flushed_nl,
                         &hd_type, &dec_ind, &last_token_ends_sp, &file_exit_value,
                         can_break, &last_else, is_procname_definition);
        
        *e_code = '\0';         /* make sure code section is null terminated */

        if ((type_code != comment) &&
            (type_code != cplus_comment) &&
            (type_code != newline) &&
            (type_code != preesc) &&
            (type_code != form_feed))
        {
            parser_state_tos->last_token = type_code;
        }

        /* Now that we've put the token on the line (in most cases),
         * consider breaking the line because it's too long.
         *
         * Don't consider the cases of `unary_op', newlines,
         * declaration types (int, etc.), if, while, for,
         * identifiers (handled at the beginning of the loop),
         * periods, or preprocessor commands. */

        if ((settings.max_col > 0) && (buf_break != NULL))
        {
            if ( ( (type_code == binary_op) ||
                   (type_code == postop) ||
                   (type_code == question) ||
                   ((type_code == colon) && (scase || (squest <= 0))) ||
                   (type_code == semicolon) ||
                   (type_code == sp_nparen) ||
                   (type_code == sp_else) ||
                   ((type_code == ident) && (*token == '\"')) ||
                   (type_code == struct_delim) ||
                   (type_code == comma)) &&
                 (output_line_length () > settings.max_col))
            {
                break_line = 1;
            }
        }
    }                           /* end of main infinite loop */
}

/******************************************************************************/
static exit_values_ty indent (
    file_buffer_ty * this_file)
{
    in_prog                     = this_file->data;
    in_prog_pos                 = this_file->data;
    in_prog_size                = this_file->size;
    squest                      = false;
    n_real_blanklines           = 0;
    postfix_blankline_requested = 0;

    clear_buf_break_list ();
    
    break_line = 0;

    if (settings.decl_com_ind <= 0)      /* if not specified by user, set this */
    {
        settings.decl_com_ind = settings.ljust_decl ? (settings.com_ind <= 10 ? 2 :
                                                       settings.com_ind - 8) :
                                                       settings.com_ind;
    }

    if (settings.continuation_indent == 0)
    {
        settings.continuation_indent = settings.ind_size;
    }

    if (settings.paren_indent == -1)
    {
        settings.paren_indent = settings.continuation_indent;
    }

    if (settings.case_brace_indent == -1)
    {
        settings.case_brace_indent = settings.ind_size;   /* This was the previous default */
    }

    fill_buffer ();             /* Fill the input buffer */

    return indent_main_loop();         /* do the work. */
}

/******************************************************************************/
static char * handle_profile (int argc, char *argv[])
{
    int i;
    char *profile_pathname = NULL;

    for (i = 1; i < argc; ++i)
    {
        if ((strcmp (argv[i], "-npro") == 0) ||
            (strcmp (argv[i], "--ignore-profile") == 0) ||
            (strcmp (argv[i], "+ignore-profile") == 0))
        {
            break;
        }
    }

    if (i >= argc)
    {
        profile_pathname = set_profile ();
    }

    return profile_pathname;
}

/******************************************************************************/
static char    * out_name        = 0; /* Points to the name of the output file */
static int       input_files     = 0; /* How many input files were specified */
static char **   in_file_names   = NULL; /* Names of all input files */
static int       max_input_files = 128; /* Initial number of input filenames to allocate. */


/******************************************************************************/
static exit_values_ty process_args (
    int       argc,
    char    * argv[],
    BOOLEAN * using_stdin)
{
    int i;
    exit_values_ty exit_status = total_success;

    for (i = 1; i < argc; ++i)
    {
        if ((*argv[i] != '-') && (*argv[i] != '+'))       /* Filename */
        {
            if (settings.expect_output_file == true)       /* Last arg was "-o" */
            {
                if (out_name != 0)
                {
                    fprintf (stderr,
                             _("indent: only one output file (2nd was %s)\n"),
                             argv[i]);
                    exit_status = invocation_error;
                    break;
                }

                if (input_files > 1)
                {
                    fprintf (stderr,
                             _("indent: only one input file when output file is specified\n"));
                    exit_status = invocation_error;
                    break;
                }

                out_name = argv[i];
                settings.expect_output_file = false;
                continue;
            }
            else
            {
                if (*using_stdin)
                {
                    fprintf (stderr,
                             _("indent: can't have filenames when specifying standard input\n"));
                    exit_status = invocation_error;
                    break;
                }

                input_files++;

                if (input_files > 1)
                {
                    if (out_name != 0)
                    {
                        fprintf (stderr,
                                 _("indent: only one input file when output file is specified\n"));
                        exit_status = invocation_error;
                        break;
                    }

                    if (settings.use_stdout != 0)
                    {
                        fprintf (stderr,
                                 _("indent: only one input file when stdout is used\n"));
                        exit_status = invocation_error;
                        break;
                    }

                    if (input_files > max_input_files)
                    {
                        max_input_files = 2 * max_input_files;
                        in_file_names =
                                (char **) xrealloc ((char *) in_file_names,
                                                    (max_input_files *
                                                     sizeof (char *)));
                    }
                }

                in_file_names[input_files - 1] = argv[i];
            }
        }
        else
        {
            /* '-' as filename means stdin. */
            
            if (strcmp (argv[i], "-") == 0)
            {
                if (input_files > 0)
                {
                    fprintf (stderr,
                             _("indent: can't have filenames when specifying standard input\n"));
                    exit_status = invocation_error;
                    break;
                }

                *using_stdin = true;
            }
            else
            {
                i += set_option (argv[i], (i < argc ? argv[i + 1] : 0), 1);
            }
        }
    }

    return exit_status;
}

/******************************************************************************/
static exit_values_ty indent_multiple_files(void)
{
    exit_values_ty exit_status = total_success;
    
    int i;
    /* When multiple input files are specified, make a backup copy
     * and then output the indented code into the same filename. */

    for (i = 0; input_files; i++, input_files--)
    {
        exit_values_ty status;
        struct stat file_stats;

        in_name = in_file_names[i];
        out_name = in_file_names[i];
        current_input = read_file(in_file_names[i], &file_stats);

        open_output(out_name, "r+");

        make_backup(current_input, &file_stats); /* Aborts on failure. */

        /* We have safely made a backup so the open file can be truncated. */
          
        reopen_output_trunc(out_name);
          
        reset_parser();
        status = indent (current_input);

        if (status > exit_status)
        {
            exit_status = status;
        }

        if (settings.preserve_mtime)
        {
            close_output(&file_stats, out_name);
        }
        else
        {
            close_output(NULL, out_name);
        }
    }
    
    return exit_status;
}

/******************************************************************************/
static exit_values_ty indent_single_file(BOOLEAN using_stdin)
{
    exit_values_ty exit_status = total_success;
    struct stat    file_stats;

    if (input_files == 0 || using_stdin)
    {
        input_files = 1;
        in_file_names[0] = "Standard input";
        in_name = in_file_names[0];
        current_input = read_stdin ();
    }
    else
    {
        /* 1 input file */

        in_name = in_file_names[0];
        current_input = read_file (in_file_names[0], &file_stats);

        if (!out_name && !settings.use_stdout)
        {
            out_name = in_file_names[0];
            make_backup (current_input, &file_stats);
        }
    }

    /* Use stdout if it was specified ("-st"), or neither input
     * nor output file was specified. */

    if (settings.use_stdout || !out_name)
    {
        open_output(NULL, NULL);
    }
    else
    {
        open_output(out_name, "w");
    }

    reset_parser ();

    exit_status = indent (current_input);

    if (input_files > 0 && !using_stdin && settings.preserve_mtime)
    {
        close_output(&file_stats, out_name);
    }
    else
    {
        close_output(NULL, out_name);
    }
    
    return exit_status;
}

/******************************************************************************/
static exit_values_ty indent_all (BOOLEAN using_stdin)
{
    exit_values_ty exit_status = total_success;

    if (input_files > 1)
    {
        exit_status = indent_multiple_files();
        
    }
    else
    {
        /* One input stream -- specified file, or stdin */
        exit_status = indent_single_file(using_stdin);
        
    }

    return exit_status;
}

/******************************************************************************/
int main (
    int     argc,
    char ** argv)
{
    int i;
    char *profile_pathname = 0;
    BOOLEAN using_stdin = false;
    exit_values_ty exit_status;

#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
    setlocale (LC_MESSAGES, "");
#endif
    bindtextdomain (PACKAGE, LOCALEDIR);
    textdomain (PACKAGE);

#if defined (_WIN32) && !defined (__CYGWIN__)
    /* wildcard expansion of commandline arguments, see wildexp.c */

    extern void wildexp (int *argc, char ***argv);

    wildexp (&argc, &argv);
#endif /* defined (_WIN32) && !defined (__CYGWIN__) */

#ifdef DEBUG
    if (debug)
    {
        debug_init ();
    }
#endif

    init_parser ();
    initialize_backups ();
    exit_status = total_success;

    input_files = 0;
    in_file_names = (char **) xmalloc (max_input_files * sizeof (char *));

    set_defaults ();

    profile_pathname = handle_profile (argc, argv);

    exit_status = process_args (argc, argv, &using_stdin);

    if (exit_status == total_success)
    {
        if (settings.verbose && profile_pathname)
        {
            fprintf (stderr, _("Read profile %s\n"), profile_pathname);
        }

        set_defaults_after ();

        exit_status = indent_all (using_stdin);
    }
    
    return (exit_status);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].