/* 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 and Eric Lloyd * Added support for -brf to place function opening brace after function * declaration. */ #include "sys.h" #if defined (HAVE_UNISTD_H) #include #endif #ifdef PRESERVE_MTIME #include #ifdef HAVE_UTIME_H #include #elif defined(HAVE_SYS_UTIME_H) #include #endif #endif #include #include #include #include #ifdef HAVE_LOCALE_H #include #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 ?: 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 * ?: 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 ? : 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); }