/** * Aligns all the stuff in m_aligned. * Re-adds 'newer' items in m_skipped. */ void AlignStack::Flush() { int last_seqnum = 0; int idx; int tmp_col; const ChunkStack::Entry *ce = NULL; chunk_t *pc; LOG_FMT(LAS, "%s: m_aligned.Len()=%d\n", __func__, m_aligned.Len()); LOG_FMT(LAS, "Flush (min=%d, max=%d)\n", m_min_col, m_max_col); if (m_aligned.Len() == 1) { // check if we have *one* typedef in the line pc = m_aligned.Get(0)->m_pc; chunk_t *temp = chunk_get_prev_type(pc, CT_TYPEDEF, pc->level); if (temp != NULL) { if (pc->orig_line == temp->orig_line) { // reset the gap only for *this* stack m_gap = 1; } } } m_last_added = 0; m_max_col = 0; /* Recalculate the max_col - it may have shifted since the last Add() */ for (idx = 0; idx < m_aligned.Len(); idx++) { pc = m_aligned.Get(idx)->m_pc; /* Set the column adjust and gap */ int col_adj = 0; int gap = 0; if (pc != pc->align.ref) { gap = pc->column - (pc->align.ref->column + pc->align.ref->len()); } chunk_t *tmp = pc; if (tmp->type == CT_TPAREN_OPEN) { tmp = chunk_get_next(tmp); } if (chunk_is_ptr_operator(tmp) && (m_star_style == SS_DANGLE)) { col_adj = pc->align.start->column - pc->column; gap = pc->align.start->column - (pc->align.ref->column + pc->align.ref->len()); } if (m_right_align) { /* Adjust the width for signed numbers */ int start_len = pc->align.start->len(); if (pc->align.start->type == CT_NEG) { tmp = chunk_get_next(pc->align.start); if ((tmp != NULL) && (tmp->type == CT_NUMBER)) { start_len += tmp->len(); } } col_adj += start_len; } pc->align.col_adj = col_adj; /* See if this pushes out the max_col */ int endcol = pc->column + col_adj; if (gap < m_gap) { endcol += m_gap - gap; } if (endcol > m_max_col) { m_max_col = endcol; } } if (cpd.settings[UO_align_on_tabstop].b && (m_aligned.Len() > 1)) { m_max_col = align_tab_column(m_max_col); } LOG_FMT(LAS, "%s: m_aligned.Len()=%d\n", __func__, m_aligned.Len()); for (idx = 0; idx < m_aligned.Len(); idx++) { ce = m_aligned.Get(idx); pc = ce->m_pc; tmp_col = m_max_col - pc->align.col_adj; if (idx == 0) { if (m_skip_first && (pc->column != tmp_col)) { LOG_FMT(LAS, "%s: %lu:%lu dropping first item due to skip_first\n", __func__, pc->orig_line, pc->orig_col); m_skip_first = false; m_aligned.Pop_Front(); Flush(); m_skip_first = true; return; } chunk_flags_set(pc, PCF_ALIGN_START); pc->align.right_align = m_right_align; pc->align.amp_style = (int)m_amp_style; pc->align.star_style = (int)m_star_style; } pc->align.gap = m_gap; pc->align.next = m_aligned.GetChunk(idx + 1); /* Indent the token, taking col_adj into account */ LOG_FMT(LAS, "%s: line %lu: '%s' to col %d (adj=%d)\n", __func__, pc->orig_line, pc->text(), tmp_col, pc->align.col_adj); align_to_column(pc, tmp_col); } if (ce != NULL) { last_seqnum = ce->m_seqnum; m_aligned.Reset(); } m_min_col = 9999; m_max_col = 0; if (m_skipped.Empty()) { /* Nothing was skipped, sync the seqnums */ m_nl_seqnum = m_seqnum; } else { /* Remove all items with seqnum < last_seqnum */ for (idx = 0; idx < m_skipped.Len(); idx++) { if (m_skipped.Get(idx)->m_seqnum < last_seqnum) { m_skipped.Zap(idx); } } m_skipped.Collapse(); /* Add all items from the skipped list */ ReAddSkipped(); } } // AlignStack::Flush
/** * Checks the progression of complex statements. * - checks for else after if * - checks for if after else * - checks for while after do * - checks for open brace in BRACE2 and BRACE_DO stages, inserts open VBRACE * - checks for open paren in PAREN1 and PAREN2 stages, complains * * @param frm The parse frame * @param pc The current chunk * @return true - done with this chunk, false - keep processing */ static bool check_complex_statements(struct parse_frame *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); c_token_t parent; chunk_t *vbrace; /* Turn an optional paren into either a real paren or a brace */ if (frm->pse[frm->pse_tos].stage == BS_OP_PAREN1) { frm->pse[frm->pse_tos].stage = (pc->type != CT_PAREN_OPEN) ? BS_BRACE2 : BS_PAREN1; } /* Check for CT_ELSE after CT_IF */ while (frm->pse[frm->pse_tos].stage == BS_ELSE) { if (pc->type == CT_ELSE) { /* Replace CT_IF with CT_ELSE on the stack & we are done */ frm->pse[frm->pse_tos].type = CT_ELSE; frm->pse[frm->pse_tos].stage = BS_ELSEIF; print_stack(LBCSSWAP, "=Swap ", frm, pc); return(true); } /* Remove the CT_IF and close the statement */ frm->pse_tos--; print_stack(LBCSPOP, "-IF-CCS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } /* Check for CT_IF after CT_ELSE */ if (frm->pse[frm->pse_tos].stage == BS_ELSEIF) { if (pc->type == CT_IF) { if (!cpd.settings[UO_indent_else_if].b || !chunk_is_newline(chunk_get_prev_nc(pc))) { /* Replace CT_ELSE with CT_IF */ set_chunk_type(pc, CT_ELSEIF); frm->pse[frm->pse_tos].type = CT_ELSEIF; frm->pse[frm->pse_tos].stage = BS_PAREN1; return(true); } } /* Jump to the 'expecting brace' stage */ frm->pse[frm->pse_tos].stage = BS_BRACE2; } /* Check for CT_CATCH or CT_FINALLY after CT_TRY or CT_CATCH */ while (frm->pse[frm->pse_tos].stage == BS_CATCH) { if ((pc->type == CT_CATCH) || (pc->type == CT_FINALLY)) { /* Replace CT_TRY with CT_CATCH on the stack & we are done */ frm->pse[frm->pse_tos].type = pc->type; frm->pse[frm->pse_tos].stage = (pc->type == CT_CATCH) ? BS_CATCH_WHEN : BS_BRACE2; print_stack(LBCSSWAP, "=Swap ", frm, pc); return(true); } /* Remove the CT_TRY and close the statement */ frm->pse_tos--; print_stack(LBCSPOP, "-TRY-CCS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } /* Check for optional paren and optional CT_WHEN after CT_CATCH */ if (frm->pse[frm->pse_tos].stage == BS_CATCH_WHEN) { if (pc->type == CT_PAREN_OPEN) // this is for the paren after "catch" { /* Replace CT_PAREN_OPEN with CT_SPAREN_OPEN */ set_chunk_type(pc, CT_SPAREN_OPEN); frm->pse[frm->pse_tos].type = pc->type; frm->pse[frm->pse_tos].stage = BS_PAREN1; return(false); } else if (pc->type == CT_WHEN) { frm->pse[frm->pse_tos].type = pc->type; frm->pse[frm->pse_tos].stage = BS_OP_PAREN1; return(true); } else if (pc->type == CT_BRACE_OPEN) { frm->pse[frm->pse_tos].stage = BS_BRACE2; return(false); } } /* Check for CT_WHILE after the CT_DO */ if (frm->pse[frm->pse_tos].stage == BS_WHILE) { if (pc->type == CT_WHILE) { set_chunk_type(pc, CT_WHILE_OF_DO); frm->pse[frm->pse_tos].type = CT_WHILE_OF_DO; //CT_WHILE; frm->pse[frm->pse_tos].stage = BS_WOD_PAREN; return(true); } LOG_FMT(LWARN, "%s:%d Error: Expected 'while', got '%s'\n", cpd.filename, pc->orig_line, pc->text()); frm->pse_tos--; print_stack(LBCSPOP, "-Error ", frm, pc); cpd.error_count++; } /* Insert a CT_VBRACE_OPEN, if needed */ if ((pc->type != CT_BRACE_OPEN) && ((frm->pse[frm->pse_tos].stage == BS_BRACE2) || (frm->pse[frm->pse_tos].stage == BS_BRACE_DO))) { parent = frm->pse[frm->pse_tos].type; vbrace = insert_vbrace_open_before(pc, frm); set_chunk_parent(vbrace, parent); frm->level++; frm->brace_level++; push_fmr_pse(frm, vbrace, BS_NONE, "+VBrace "); frm->pse[frm->pse_tos].parent = parent; /* update the level of pc */ pc->level = frm->level; pc->brace_level = frm->brace_level; /* Mark as a start of a statement */ frm->stmt_count = 0; frm->expr_count = 0; pc->flags |= PCF_STMT_START | PCF_EXPR_START; frm->stmt_count = 1; frm->expr_count = 1; LOG_FMT(LSTMT, "%d] 2.marked %s as stmt start\n", pc->orig_line, pc->text()); } /* Verify open paren in complex statement */ if ((pc->type != CT_PAREN_OPEN) && ((frm->pse[frm->pse_tos].stage == BS_PAREN1) || (frm->pse[frm->pse_tos].stage == BS_WOD_PAREN))) { LOG_FMT(LWARN, "%s:%d Error: Expected '(', got '%s' for '%s'\n", cpd.filename, pc->orig_line, pc->text(), get_token_name(frm->pse[frm->pse_tos].type)); /* Throw out the complex statement */ frm->pse_tos--; print_stack(LBCSPOP, "-Error ", frm, pc); cpd.error_count++; } return(false); } // check_complex_statements
/** * Skips the next bit of whatever and returns the type of block. * * pc.str is the input text. * pc.len in the output length. * pc.type is the output type * pc.column is output column * * @param pc The structure to update, str is an input. * @return true/false - whether anything was parsed */ static bool parse_next(tok_ctx& ctx, chunk_t& pc) { const chunk_tag_t *punc; int ch, ch1; if (!ctx.more()) { //fprintf(stderr, "All done!\n"); return(false); } /* Save off the current column */ pc.orig_line = ctx.c.row; pc.column = ctx.c.col; pc.orig_col = ctx.c.col; pc.type = CT_NONE; pc.nl_count = 0; pc.flags = 0; /* If it is turned off, we put everything except newlines into CT_UNKNOWN */ if (cpd.unc_off) { if (parse_ignored(ctx, pc)) { return(true); } } /** * Parse whitespace */ if (parse_whitespace(ctx, pc)) { return(true); } /** * Handle unknown/unhandled preprocessors */ if ((cpd.in_preproc > CT_PP_BODYCHUNK) && (cpd.in_preproc <= CT_PP_OTHER)) { pc.str.clear(); tok_info ss; ctx.save(ss); /* Chunk to a newline or comment */ pc.type = CT_PREPROC_BODY; int last = 0; while (ctx.more()) { int ch = ctx.peek(); if ((ch == '\n') || (ch == '\r')) { /* Back off if this is an escaped newline */ if (last == '\\') { ctx.restore(ss); pc.str.pop_back(); } break; } /* Quit on a C++ comment start */ if ((ch == '/') && (ctx.peek(1) == '/')) { break; } last = ch; ctx.save(ss); pc.str.append(ctx.get()); } if (pc.str.size() > 0) { return(true); } } /** * Detect backslash-newline */ if ((ctx.peek() == '\\') && parse_bs_newline(ctx, pc)) { return(true); } /** * Parse comments */ if (parse_comment(ctx, pc)) { return(true); } /* Check for C# literal strings, ie @"hello" and identifiers @for*/ if (((cpd.lang_flags & LANG_CS) != 0) && (ctx.peek() == '@')) { if (ctx.peek(1) == '"') { parse_cs_string(ctx, pc); return(true); } /* check for non-keyword identifiers such as @if @switch, etc */ if (CharTable::IsKw1(ctx.peek(1))) { parse_word(ctx, pc, true); return(true); } } /* handle C++0x strings u8"x" u"x" U"x" R"x" u8R"XXX(I'm a "raw UTF-8" string.)XXX" */ ch = ctx.peek(); if (((cpd.lang_flags & LANG_CPP) != 0) && ((ch == 'u') || (ch == 'U') || (ch == 'R'))) { int idx = 0; bool is_real = false; if ((ch == 'u') && (ctx.peek(1) == '8')) { idx = 2; } else if (unc_tolower(ch) == 'u') { idx++; } if (ctx.peek(idx) == 'R') { idx++; is_real = true; } if (ctx.peek(idx) == '"') { if (is_real) { if (parse_cr_string(ctx, pc, idx)) { return(true); } } else { if (parse_string(ctx, pc, idx, true)) { parse_suffix(ctx, pc, true); return(true); } } } } /* PAWN specific stuff */ if ((cpd.lang_flags & LANG_PAWN) != 0) { /* Check for PAWN strings: \"hi" or !"hi" or !\"hi" or \!"hi" */ if ((ctx.peek() == '\\') || (ctx.peek() == '!')) { if (ctx.peek(1) == '"') { parse_string(ctx, pc, 1, (ctx.peek() == '!')); return(true); } else if (((ctx.peek(1) == '\\') || (ctx.peek(1) == '!')) && (ctx.peek(2) == '"')) { parse_string(ctx, pc, 2, false); return(true); } } } /** * Parse strings and character constants */ if (parse_number(ctx, pc)) { return(true); } if ((cpd.lang_flags & LANG_D) != 0) { /* D specific stuff */ if (d_parse_string(ctx, pc)) { return(true); } } else { /* Not D stuff */ /* Check for L'a', L"abc", 'a', "abc", <abc> strings */ ch = ctx.peek(); ch1 = ctx.peek(1); if ((((ch == 'L') || (ch == 'S')) && ((ch1 == '"') || (ch1 == '\''))) || (ch == '"') || (ch == '\'') || ((ch == '<') && (cpd.in_preproc == CT_PP_INCLUDE))) { parse_string(ctx, pc, unc_isalpha(ch) ? 1 : 0, true); return(true); } if ((ch == '<') && (cpd.in_preproc == CT_PP_DEFINE)) { if (chunk_get_tail()->type == CT_MACRO) { /* We have "#define XXX <", assume '<' starts an include string */ parse_string(ctx, pc, 0, false); return(true); } } } /* Check for Objective C literals */ if ((cpd.lang_flags & LANG_OC) && (ctx.peek() == '@')) { int nc = ctx.peek(1); if ((nc == '"') || (nc == '\'')) { /* literal string */ parse_string(ctx, pc, 1, true); return true; } else if ((nc >= '0') && (nc <= '9')) { /* literal number */ pc.str.append(ctx.get()); /* store the '@' */ parse_number(ctx, pc); return true; } } /* Check for pawn/ObjectiveC/Java and normal identifiers */ if (CharTable::IsKw1(ctx.peek()) || ((ctx.peek() == '@') && CharTable::IsKw1(ctx.peek(1)))) { parse_word(ctx, pc, false); return(true); } /* see if we have a punctuator */ char punc_txt[4]; punc_txt[0] = ctx.peek(); punc_txt[1] = ctx.peek(1); punc_txt[2] = ctx.peek(2); punc_txt[3] = ctx.peek(3); if ((punc = find_punctuator(punc_txt, cpd.lang_flags)) != NULL) { int cnt = strlen(punc->tag); while (cnt--) { pc.str.append(ctx.get()); } pc.type = punc->type; pc.flags |= PCF_PUNCTUATOR; return(true); } /* throw away this character */ pc.type = CT_UNKNOWN; pc.str.append(ctx.get()); LOG_FMT(LWARN, "%s:%d Garbage in col %d: %x\n", cpd.filename, pc.orig_line, (int)ctx.c.col, pc.str[0]); cpd.error_count++; return(true); }
int main(int argc, char *argv[]) { string cfg_file; const char *parsed_file = NULL; const char *source_file = NULL; const char *output_file = NULL; const char *source_list = NULL; log_mask_t mask; int idx; const char *p_arg; /* If ran without options... check keyword sort and show the usage info */ if (argc == 1) { keywords_are_sorted(); usage_exit(NULL, argv[0], EXIT_SUCCESS); } /* Build options map */ register_options(); Args arg(argc, argv); if (arg.Present("--version") || arg.Present("-v")) { version_exit(); } if (arg.Present("--help") || arg.Present("-h") || arg.Present("--usage") || arg.Present("-?")) { usage_exit(NULL, argv[0], EXIT_SUCCESS); } if (arg.Present("--show-config")) { print_options(stdout); return EXIT_SUCCESS; } #ifdef WIN32 /* tell windoze not to change what I write to stdout */ (void)_setmode(_fileno(stdout), _O_BINARY); #endif /* Init logging */ log_init(stderr); if (arg.Present("-q")) { logmask_from_string("", mask); log_set_mask(mask); } if (((p_arg = arg.Param("-L")) != NULL) || ((p_arg = arg.Param("--log")) != NULL)) { logmask_from_string(p_arg, mask); log_set_mask(mask); } cpd.frag = arg.Present("--frag"); if (arg.Present("--decode")) { idx = 1; while ((p_arg = arg.Unused(idx)) != NULL) { log_pcf_flags(LSYS, strtoul(p_arg, NULL, 16)); } return EXIT_SUCCESS; } /* Get the config file name */ if (((p_arg = arg.Param("--config")) != NULL) || ((p_arg = arg.Param("-c")) != NULL)) { cfg_file = p_arg; } /* Try to find a config file at an alternate location */ if (cfg_file.empty()) { if (!unc_getenv("UNCRUSTIFY_CONFIG", cfg_file)) { string home; if (unc_homedir(home)) { struct stat tmp_stat; string path; path = home + "/uncrustify.cfg"; if (stat(path.c_str(), &tmp_stat) == 0) { cfg_file = path; } else { path = home + "/.uncrustify.cfg"; if (stat(path.c_str(), &tmp_stat) == 0) { cfg_file = path; } } } } } /* Get the parsed file name */ if (((parsed_file = arg.Param("--parsed")) != NULL) || ((parsed_file = arg.Param("-p")) != NULL)) { LOG_FMT(LNOTE, "Will export parsed data to: %s\n", parsed_file); } /* Enable log sevs? */ if (arg.Present("-s") || arg.Present("--show")) { log_show_sev(true); } /* Load the config file */ set_option_defaults(); /* Load type files */ idx = 0; while ((p_arg = arg.Params("-t", idx)) != NULL) { load_keyword_file(p_arg); } /* add types */ idx = 0; while ((p_arg = arg.Params("--type", idx)) != NULL) { add_keyword(p_arg, CT_TYPE); } /* Load define files */ idx = 0; while ((p_arg = arg.Params("-d", idx)) != NULL) { load_define_file(p_arg); } /* add defines */ idx = 0; while ((p_arg = arg.Params("--define", idx)) != NULL) { add_define(p_arg, NULL); } /* Check for a language override */ if ((p_arg = arg.Param("-l")) != NULL) { cpd.lang_flags = language_from_tag(p_arg); if (cpd.lang_flags == 0) { LOG_FMT(LWARN, "Ignoring unknown language: %s\n", p_arg); } else { cpd.lang_forced = true; } } /* Get the source file name */ if (((source_file = arg.Param("--file")) == NULL) && ((source_file = arg.Param("-f")) == NULL)) { // not using a single file, source_file is NULL } if (((source_list = arg.Param("--files")) == NULL) && ((source_list = arg.Param("-F")) == NULL)) { // not using a file list, source_list is NULL } const char *prefix = arg.Param("--prefix"); const char *suffix = arg.Param("--suffix"); bool no_backup = arg.Present("--no-backup"); bool replace = arg.Present("--replace"); bool keep_mtime = arg.Present("--mtime"); bool update_config = arg.Present("--update-config"); bool update_config_wd = arg.Present("--update-config-with-doc"); bool detect = arg.Present("--detect"); /* Grab the output override */ output_file = arg.Param("-o"); LOG_FMT(LDATA, "config_file = %s\n", cfg_file.c_str()); LOG_FMT(LDATA, "output_file = %s\n", (output_file != NULL) ? output_file : "null"); LOG_FMT(LDATA, "source_file = %s\n", (source_file != NULL) ? source_file : "null"); LOG_FMT(LDATA, "source_list = %s\n", (source_list != NULL) ? source_list : "null"); LOG_FMT(LDATA, "prefix = %s\n", (prefix != NULL) ? prefix : "null"); LOG_FMT(LDATA, "suffix = %s\n", (suffix != NULL) ? suffix : "null"); LOG_FMT(LDATA, "replace = %d\n", replace); LOG_FMT(LDATA, "no_backup = %d\n", no_backup); LOG_FMT(LDATA, "detect = %d\n", detect); if (replace || no_backup) { if ((prefix != NULL) || (suffix != NULL)) { usage_exit("Cannot use --replace with --prefix or --suffix", argv[0], 66); } if ((source_file != NULL) || (output_file != NULL)) { usage_exit("Cannot use --replace or --no-backup with -f or -o", argv[0], 66); } } else { if ((prefix == NULL) && (suffix == NULL)) { suffix = ".uncrustify"; } } /* Try to load the config file, if available. * It is optional for "--universalindent" and "--detect", but required for * everything else. */ if (!cfg_file.empty()) { cpd.filename = cfg_file.c_str(); if (load_option_file(cpd.filename) < 0) { usage_exit("Unable to load the config file", argv[0], 56); } } if (arg.Present("--universalindent")) { FILE *pfile = stdout; if (output_file != NULL) { pfile = fopen(output_file, "w"); if (pfile == NULL) { fprintf(stderr, "Unable to open %s for write: %s (%d)\n", output_file, strerror(errno), errno); return EXIT_FAILURE; } } print_universal_indent_cfg(pfile); return EXIT_SUCCESS; } if (detect) { file_mem fm; if ((source_file == NULL) || (source_list != NULL)) { fprintf(stderr, "The --detect option requires a single input file\n"); return EXIT_FAILURE; } /* Do some simple language detection based on the filename extension */ if (!cpd.lang_forced || (cpd.lang_flags == 0)) { cpd.lang_flags = language_from_filename(source_file); } /* Try to read in the source file */ if (load_mem_file(source_file, fm) < 0) { LOG_FMT(LERR, "Failed to load (%s)\n", source_file); cpd.error_count++; return EXIT_FAILURE; } uncrustify_start(fm.data); detect_options(); uncrustify_end(); redir_stdout(output_file); save_option_file(stdout, update_config_wd); return EXIT_SUCCESS; } /* Everything beyond this point requires a config file, so complain and * bail if we don't have one. */ if (cfg_file.empty()) { usage_exit("Specify the config file with '-c file' or set UNCRUSTIFY_CONFIG", argv[0], 58); } /* * Done parsing args */ if (update_config || update_config_wd) { redir_stdout(output_file); save_option_file(stdout, update_config_wd); return EXIT_SUCCESS; } /* Check for unused args (ignore them) */ idx = 1; p_arg = arg.Unused(idx); /* Check args - for multifile options */ if ((source_list != NULL) || (p_arg != NULL)) { if (source_file != NULL) { usage_exit("Cannot specify both the single file option and a multi-file option.", argv[0], 67); } if (output_file != NULL) { usage_exit("Cannot specify -o with a multi-file option.", argv[0], 68); } } /* This relies on cpd.filename being the config file name */ load_header_files(); if ((source_file == NULL) && (source_list == NULL) && (p_arg == NULL)) { /* no input specified, so use stdin */ if (cpd.lang_flags == 0) { cpd.lang_flags = LANG_C; } redir_stdout(output_file); file_mem fm; if (!read_stdin(fm)) { LOG_FMT(LERR, "Failed to read stdin\n"); return(100); } cpd.filename = "stdin"; /* Done reading from stdin */ LOG_FMT(LSYS, "Parsing: %d bytes (%d chars) from stdin as language %s\n", (int)fm.raw.size(), (int)fm.data.size(), language_to_string(cpd.lang_flags)); uncrustify_file(fm, stdout, parsed_file); } else if (source_file != NULL) { /* Doing a single file */ do_source_file(source_file, output_file, parsed_file, no_backup, keep_mtime); } else { /* Doing multiple files */ if (prefix != NULL) { LOG_FMT(LSYS, "Output prefix: %s/\n", prefix); } if (suffix != NULL) { LOG_FMT(LSYS, "Output suffix: %s\n", suffix); } /* Do the files on the command line first */ idx = 1; while ((p_arg = arg.Unused(idx)) != NULL) { char outbuf[1024]; do_source_file(p_arg, make_output_filename(outbuf, sizeof(outbuf), p_arg, prefix, suffix), NULL, no_backup, keep_mtime); } if (source_list != NULL) { process_source_list(source_list, prefix, suffix, no_backup, keep_mtime); } } clear_keyword_file(); clear_defines(); return((cpd.error_count != 0) ? EXIT_FAILURE : EXIT_SUCCESS); }
/** * Called when a statement was just closed and the pse_tos was just * decremented. * * - if the TOS is now VBRACE, insert a CT_VBRACE_CLOSE and recurse. * - if the TOS is a complex statement, call handle_complex_close() * * @return true - done with this chunk, false - keep processing */ bool close_statement(struct parse_frame *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); chunk_t *vbc = pc; LOG_FMT(LTOK, "%s:%d] %s '%s' type %s stage %d\n", __func__, pc->orig_line, get_token_name(pc->type), pc->text(), get_token_name(frm->pse[frm->pse_tos].type), frm->pse[frm->pse_tos].stage); if (cpd.consumed) { frm->stmt_count = 0; frm->expr_count = 0; LOG_FMT(LSTMT, "%s: %d> reset2 stmt on %s\n", __func__, pc->orig_line, pc->text()); } /** * If we are in a virtual brace and we are not ON a CT_VBRACE_CLOSE add one */ if (frm->pse[frm->pse_tos].type == CT_VBRACE_OPEN) { /* If the current token has already been consumed, then add after it */ if (cpd.consumed) { insert_vbrace_close_after(pc, frm); } else { /* otherwise, add before it and consume the vbrace */ vbc = chunk_get_prev_ncnl(pc); vbc = insert_vbrace_close_after(vbc, frm); set_chunk_parent(vbc, frm->pse[frm->pse_tos].parent); frm->level--; frm->brace_level--; frm->pse_tos--; /* Update the token level */ pc->level = frm->level; pc->brace_level = frm->brace_level; print_stack(LBCSPOP, "-CS VB ", frm, pc); /* And repeat the close */ close_statement(frm, pc); return(true); } } /* See if we are done with a complex statement */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { if (handle_complex_close(frm, vbc)) { return(true); } } return(false); } // close_statement
/** * Step forward and count the number of semi colons at the current level. * Abort if more than 1 or if we enter a preprocessor */ static void examine_brace(chunk_t *bopen) { chunk_t *pc; chunk_t *next; chunk_t *prev = NULL; int semi_count = 0; int level = bopen->level + 1; bool hit_semi = false; bool was_fcn = false; int nl_max = cpd.settings[UO_mod_full_brace_nl].n; int nl_count = 0; int if_count = 0; int br_count = 0; LOG_FMT(LBRDEL, "%s: start on %d : ", __func__, bopen->orig_line); pc = chunk_get_next_nc(bopen); while ((pc != NULL) && (pc->level >= level)) { if ((pc->flags & PCF_IN_PREPROC) != 0) { LOG_FMT(LBRDEL, " PREPROC\n"); return; } if (chunk_is_newline(pc)) { nl_count += pc->nl_count; if ((nl_max > 0) && (nl_count > nl_max)) { LOG_FMT(LBRDEL, " exceeded %d newlines\n", nl_max); return; } } else { if (pc->type == CT_BRACE_OPEN) { br_count++; } else if (pc->type == CT_BRACE_CLOSE) { br_count--; if (br_count == 0) { next = chunk_get_next_ncnl(pc, CNAV_PREPROC); if ((next == NULL) || (next->type != CT_BRACE_CLOSE)) { LOG_FMT(LBRDEL, " junk after close brace\n"); return; } } } else if ((pc->type == CT_IF) || (pc->type == CT_ELSEIF)) { if (br_count == 0) { if_count++; } } if (pc->level == level) { if ((semi_count > 0) && hit_semi) { /* should have bailed due to close brace level drop */ LOG_FMT(LBRDEL, " no close brace\n"); return; } LOG_FMT(LBRDEL, " [%s %d-%d]", pc->str.c_str(), pc->orig_line, semi_count); if (pc->type == CT_ELSE) { LOG_FMT(LBRDEL, " bailed on %s on line %d\n", pc->str.c_str(), pc->orig_line); return; } was_fcn = (prev != NULL) && (prev->type == CT_FPAREN_CLOSE); if (chunk_is_semicolon(pc) || (pc->type == CT_IF) || (pc->type == CT_ELSEIF) || (pc->type == CT_FOR) || (pc->type == CT_DO) || (pc->type == CT_WHILE) || (pc->type == CT_SWITCH) || (pc->type == CT_USING_STMT) || ((pc->type == CT_BRACE_OPEN) && was_fcn)) { hit_semi |= chunk_is_semicolon(pc); if (++semi_count > 1) { LOG_FMT(LBRDEL, " bailed on %d because of %s on line %d\n", bopen->orig_line, pc->str.c_str(), pc->orig_line); return; } } } } prev = pc; pc = chunk_get_next_nc(pc); } if (pc == NULL) { LOG_FMT(LBRDEL, " NULL\n"); return; } LOG_FMT(LBRDEL, " - end on '%s' on line %d. if_count=%d semi_count=%d\n", get_token_name(pc->type), pc->orig_line, if_count, semi_count); if (pc->type == CT_BRACE_CLOSE) { next = chunk_get_next_ncnl(pc); while ((next != NULL) && (next->type == CT_VBRACE_CLOSE)) { next = chunk_get_next_ncnl(next); } LOG_FMT(LBRDEL, " next is '%s'\n", get_token_name(next->type)); if ((if_count > 0) && ((next->type == CT_ELSE) || (next->type == CT_ELSEIF))) { LOG_FMT(LBRDEL, " bailed on because 'else' is next and %d ifs\n", if_count); return; } if (semi_count > 0) { if (bopen->parent_type == CT_ELSE) { next = chunk_get_next_ncnl(bopen); if (next->type == CT_IF) { prev = chunk_get_prev_ncnl(bopen); LOG_FMT(LBRDEL, " else-if removing braces on line %d and %d\n", bopen->orig_line, pc->orig_line); chunk_del(bopen); chunk_del(pc); newline_del_between(prev, next); if (cpd.settings[UO_nl_else_if].a & AV_ADD) { newline_add_between(prev, next); } return; } } /* we have a pair of braces with only 1 statement inside */ convert_brace(bopen); convert_brace(pc); LOG_FMT(LBRDEL, " removing braces on line %d and %d\n", bopen->orig_line, pc->orig_line); } else { LOG_FMT(LBRDEL, " empty statement\n"); } } else { LOG_FMT(LBRDEL, " not a close brace? - '%s'\n", pc->str.c_str()); } }
/** * Traverse the if chain and see if all can be removed */ static void process_if_chain(chunk_t *br_start) { chunk_t *braces[256]; chunk_t *br_close; int br_cnt = 0; chunk_t *pc; bool must_have_braces = false; bool tmp; pc = br_start; LOG_FMT(LBRCH, "%s: if starts on line %d\n", __func__, br_start->orig_line); while (pc != NULL) { if (pc->type == CT_BRACE_OPEN) { tmp = can_remove_braces(pc); LOG_FMT(LBRCH, " [%d] line %d - can%s remove %s\n", br_cnt, pc->orig_line, tmp ? "" : "not", get_token_name(pc->type)); if (!tmp) { must_have_braces = true; } } else { tmp = should_add_braces(pc); if (tmp) { must_have_braces = true; } LOG_FMT(LBRCH, " [%d] line %d - %s %s\n", br_cnt, pc->orig_line, tmp ? "should add" : "ignore", get_token_name(pc->type)); } braces[br_cnt++] = pc; br_close = chunk_skip_to_match(pc, CNAV_PREPROC); if (br_close == NULL) { break; } braces[br_cnt++] = br_close; pc = chunk_get_next_ncnl(br_close, CNAV_PREPROC); if ((pc == NULL) || (pc->type != CT_ELSE)) { break; } pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); if ((pc != NULL) && (pc->type == CT_ELSEIF)) { while ((pc != NULL) && (pc->type != CT_VBRACE_OPEN) && (pc->type != CT_BRACE_OPEN)) { pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); } } if (pc == NULL) { break; } if ((pc->type != CT_BRACE_OPEN) && (pc->type != CT_VBRACE_OPEN)) { break; } } if (must_have_braces) { LOG_FMT(LBRCH, "%s: add braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { braces[br_cnt]->flags |= PCF_KEEP_BRACE; if ((braces[br_cnt]->type == CT_VBRACE_OPEN) || (braces[br_cnt]->type == CT_VBRACE_CLOSE)) { LOG_FMT(LBRCH, " %d", braces[br_cnt]->orig_line); convert_vbrace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " {%d}", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } else { LOG_FMT(LBRCH, "%s: remove braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { if ((braces[br_cnt]->type == CT_BRACE_OPEN) || (braces[br_cnt]->type == CT_BRACE_CLOSE)) { LOG_FMT(LBRCH, " {%d}", braces[br_cnt]->orig_line); convert_brace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " %d", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } }
/** * Scans a line for stuff to align on. * * We trigger on BRACE_OPEN, FPAREN_OPEN, ASSIGN, and COMMA. * We want to align the NEXT item. */ static chunk_t *scan_ib_line(chunk_t *start, bool first_pass) { chunk_t *pc; chunk_t *next; chunk_t *prev_match = NULL; int token_width; int idx = 0; bool last_was_comment = false; /* Skip past C99 "[xx] =" stuff */ if (start->type == CT_SQUARE_OPEN) { start->parent_type = CT_TSQUARE; start = chunk_get_next_type(start, CT_ASSIGN, start->level); start = chunk_get_next_ncnl(start); cpd.al_c99_array = true; } pc = start; if (pc != NULL) { LOG_FMT(LSIB, "%s: start=%s col %d/%d line %d\n", __func__, get_token_name(pc->type), pc->column, pc->orig_col, pc->orig_line); } while ((pc != NULL) && !chunk_is_newline(pc) && (pc->level >= start->level)) { //LOG_FMT(LSIB, "%s: '%.*s' col %d/%d line %d\n", __func__, // pc->len, pc->str, pc->column, pc->orig_col, pc->orig_line); next = chunk_get_next(pc); if ((next == NULL) || chunk_is_comment(next)) { /* do nothing */ } else if ((pc->type == CT_ASSIGN) || (pc->type == CT_BRACE_OPEN) || (pc->type == CT_BRACE_CLOSE) || (pc->type == CT_COMMA)) { token_width = space_col_align(pc, next); /*TODO: need to handle missing structure defs? ie NULL vs { ... } ?? */ /* Is this a new entry? */ if (idx >= cpd.al_cnt) { LOG_FMT(LSIB, " - New [%d] %.2d/%d - %10.10s\n", idx, pc->column, token_width, get_token_name(pc->type)); cpd.al[cpd.al_cnt].type = pc->type; cpd.al[cpd.al_cnt].col = pc->column; cpd.al[cpd.al_cnt].len = token_width; cpd.al_cnt++; idx++; last_was_comment = false; } else { /* expect to match stuff */ if (cpd.al[idx].type == pc->type) { LOG_FMT(LSIB, " - Match [%d] %.2d/%d - %10.10s", idx, pc->column, token_width, get_token_name(pc->type)); /* Shift out based on column */ if (prev_match == NULL) { if (pc->column > cpd.al[idx].col) { LOG_FMT(LSIB, " [ pc->col(%d) > col(%d) ] ", pc->column, cpd.al[idx].col); ib_shift_out(idx, pc->column - cpd.al[idx].col); cpd.al[idx].col = pc->column; } } else if (idx > 0) { int min_col_diff = pc->column - prev_match->column; int cur_col_diff = cpd.al[idx].col - cpd.al[idx - 1].col; if (cur_col_diff < min_col_diff) { LOG_FMT(LSIB, " [ min_col_diff(%d) > cur_col_diff(%d) ] ", min_col_diff, cur_col_diff); ib_shift_out(idx, min_col_diff - cur_col_diff); } } LOG_FMT(LSIB, " - now col %d, len %d\n", cpd.al[idx].col, cpd.al[idx].len); idx++; } } prev_match = pc; } last_was_comment = chunk_is_comment(pc); pc = chunk_get_next_nc(pc); } //if (last_was_comment && (cpd.al[cpd.al_cnt - 1].type == CT_COMMA)) //{ // cpd.al_cnt--; //} return(pc); }
/** * Generically aligns on '=', '{', '(' and item after ',' * It scans the first line and picks up the location of those tags. * It then scans subsequent lines and adjusts the column. * Finally it does a second pass to align everything. * * Aligns all the '=' signs in stucture assignments. * a = { * .a = 1; * .type = fast; * }; * * And aligns on '{', numbers, strings, words. * colors[] = { * {"red", {255, 0, 0}}, {"blue", { 0, 255, 0}}, * {"green", { 0, 0, 255}}, {"purple", {255, 255, 0}}, * }; * * For the C99 indexed array assignment, the leading []= is skipped (no aligning) * struct foo_t bars[] = * { * [0] = { .name = "bar", * .age = 21 }, * [1] = { .name = "barley", * .age = 55 }, * }; * * NOTE: this assumes that spacing is at the minimum correct spacing (ie force) * if it isn't, some extra spaces will be inserted. * * @param start Points to the open brace chunk */ static void align_init_brace(chunk_t *start) { int idx; chunk_t *pc; chunk_t *next; chunk_t *prev; chunk_t *num_token = NULL; cpd.al_cnt = 0; cpd.al_c99_array = false; LOG_FMT(LALBR, "%s: line %d, col %d\n", __func__, start->orig_line, start->orig_col); pc = chunk_get_next_ncnl(start); pc = scan_ib_line(pc, true); if ((pc == NULL) || ((pc->type == CT_BRACE_CLOSE) && (pc->parent_type == CT_ASSIGN))) { /* single line - nothing to do */ return; } do { pc = scan_ib_line(pc, false); /* debug dump the current frame */ align_log_al(LALBR, pc->orig_line); while (chunk_is_newline(pc)) { pc = chunk_get_next(pc); } } while ((pc != NULL) && (pc->level > start->level)); /* debug dump the current frame */ align_log_al(LALBR, start->orig_line); if (cpd.settings[UO_align_on_tabstop].b && (cpd.al_cnt >= 1) && (cpd.al[0].type == CT_ASSIGN)) { int rem = (cpd.al[0].col - 1) % cpd.settings[UO_output_tab_size].n; if (rem != 0) { LOG_FMT(LALBR, "%s: col=%d rem=%d", __func__, cpd.al[0].col, rem); cpd.al[0].col += cpd.settings[UO_output_tab_size].n - rem; } } pc = chunk_get_next(start); idx = 0; do { if ((idx == 0) && (pc->type == CT_SQUARE_OPEN)) { pc = chunk_get_next_type(pc, CT_ASSIGN, pc->level); pc = chunk_get_next(pc); if (pc != NULL) { LOG_FMT(LALBR, " -%d- skipped '[] =' to %s\n", pc->orig_line, get_token_name(pc->type)); } continue; } next = pc; if (idx < cpd.al_cnt) { LOG_FMT(LALBR, " (%d) check %s vs %s -- ", idx, get_token_name(pc->type), get_token_name(cpd.al[idx].type)); if (pc->type == cpd.al[idx].type) { if ((idx == 0) && cpd.al_c99_array) { prev = chunk_get_prev(pc); if (chunk_is_newline(prev)) { pc->flags |= PCF_DONT_INDENT; } } LOG_FMT(LALBR, " [%.*s] to col %d\n", pc->len, pc->str, cpd.al[idx].col); if (num_token != NULL) { int col_diff = pc->column - num_token->column; reindent_line(num_token, cpd.al[idx].col - col_diff); //LOG_FMT(LSYS, "-= %d =- NUM indent [%.*s] col=%d diff=%d\n", // num_token->orig_line, // num_token->len, num_token->str, cpd.al[idx - 1].col, col_diff); num_token->flags |= PCF_WAS_ALIGNED; num_token = NULL; } /* Comma's need to 'fall back' to the previous token */ if (pc->type == CT_COMMA) { next = chunk_get_next(pc); if ((next != NULL) && !chunk_is_newline(next)) { //LOG_FMT(LSYS, "-= %d =- indent [%.*s] col=%d len=%d\n", // next->orig_line, // next->len, next->str, cpd.al[idx].col, cpd.al[idx].len); if ((idx < (cpd.al_cnt - 1)) && cpd.settings[UO_align_number_left].b && ((next->type == CT_NUMBER_FP) || (next->type == CT_NUMBER) || (next->type == CT_POS) || (next->type == CT_NEG))) { /* Need to wait until the next match to indent numbers */ num_token = next; } else { reindent_line(next, cpd.al[idx].col + cpd.al[idx].len); next->flags |= PCF_WAS_ALIGNED; } } } else { /* first item on the line */ reindent_line(pc, cpd.al[idx].col); pc->flags |= PCF_WAS_ALIGNED; /* see if we need to right-align a number */ if ((idx < (cpd.al_cnt - 1)) && cpd.settings[UO_align_number_left].b) { next = chunk_get_next(pc); if ((next != NULL) && !chunk_is_newline(next) && ((next->type == CT_NUMBER_FP) || (next->type == CT_NUMBER) || (next->type == CT_POS) || (next->type == CT_NEG))) { /* Need to wait until the next match to indent numbers */ num_token = next; } } } idx++; } else { LOG_FMT(LALBR, " no match\n"); } } if (chunk_is_newline(pc) || chunk_is_newline(next)) { idx = 0; } pc = chunk_get_next(pc); } while ((pc != NULL) && (pc->level > start->level)); }
/** * This renders the chunk list to a file. */ void output_text(FILE *pfile) { chunk_t *pc; chunk_t *prev; int cnt; int lvlcol; bool allow_tabs; cpd.fout = pfile; cpd.did_newline = 1; cpd.column = 1; if (cpd.bom) { write_bom(pfile, cpd.enc); } if (cpd.frag_cols > 0) { int indent = cpd.frag_cols - 1; for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc)) { pc->column += indent; pc->column_indent += indent; } cpd.frag_cols = 0; } for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc)) { if (pc->type == CT_NEWLINE) { for (cnt = 0; cnt < pc->nl_count; cnt++) { add_char('\n'); } cpd.did_newline = 1; cpd.column = 1; LOG_FMT(LOUTIND, " xx\n"); } else if (pc->type == CT_NL_CONT) { /* FIXME: this really shouldn't be done here! */ if ((pc->flags & PCF_WAS_ALIGNED) == 0) { if (cpd.settings[UO_sp_before_nl_cont].a & AV_REMOVE) { pc->column = cpd.column + (cpd.settings[UO_sp_before_nl_cont].a == AV_FORCE); } else { /* Try to keep the same relative spacing */ prev = chunk_get_prev(pc); while ((prev != NULL) && (prev->orig_col == 0) && (prev->nl_count == 0)) { prev = chunk_get_prev(prev); } if ((prev != NULL) && (prev->nl_count == 0)) { int orig_sp = (pc->orig_col - prev->orig_col_end); pc->column = cpd.column + orig_sp; if ((cpd.settings[UO_sp_before_nl_cont].a != AV_IGNORE) && (pc->column < (cpd.column + 1))) { pc->column = cpd.column + 1; } } } } output_to_column(pc->column, (cpd.settings[UO_indent_with_tabs].n == 2)); add_char('\\'); add_char('\n'); cpd.did_newline = 1; cpd.column = 1; LOG_FMT(LOUTIND, " \\xx\n"); } else if (pc->type == CT_COMMENT_MULTI) { if (cpd.settings[UO_cmt_indent_multi].b) { output_comment_multi(pc); } else { output_comment_multi_simple(pc); } } else if (pc->type == CT_COMMENT_CPP) { pc = output_comment_cpp(pc); } else if (pc->type == CT_COMMENT) { pc = output_comment_c(pc); } else if ((pc->type == CT_JUNK) || (pc->type == CT_IGNORED)) { /* do not adjust the column for junk */ add_text(pc->str); } else if (pc->len() == 0) { /* don't do anything for non-visible stuff */ LOG_FMT(LOUTIND, " <%d> -", pc->column); } else { /* indent to the 'level' first */ if (cpd.did_newline) { if (cpd.settings[UO_indent_with_tabs].n == 1) { /* FIXME: it would be better to properly set column_indent in * indent_text(), but this hack for '}' and ':' seems to work. */ if ((pc->type == CT_BRACE_CLOSE) || chunk_is_str(pc, ":", 1) || (pc->type == CT_PREPROC)) { lvlcol = pc->column; } else { lvlcol = pc->column_indent; if (lvlcol > pc->column) { lvlcol = pc->column; } } if (lvlcol > 1) { output_to_column(lvlcol, true); } } allow_tabs = (cpd.settings[UO_indent_with_tabs].n == 2) || (chunk_is_comment(pc) && (cpd.settings[UO_indent_with_tabs].n != 0)); LOG_FMT(LOUTIND, " %d> col %d/%d - ", pc->orig_line, pc->column, cpd.column); } else { /** * Reformatting multi-line comments can screw up the column. * Make sure we don't mess up the spacing on this line. * This has to be done here because comments are not formatted * until the output phase. */ if (pc->column < cpd.column) { reindent_line(pc, cpd.column); } /* not the first item on a line */ prev = chunk_get_prev(pc); allow_tabs = (cpd.settings[UO_align_with_tabs].b && ((pc->flags & PCF_WAS_ALIGNED) != 0) && ((prev->column + prev->len() + 1) != pc->column)); if (cpd.settings[UO_align_keep_tabs].b) { allow_tabs |= pc->after_tab; } LOG_FMT(LOUTIND, " %d(%d) -", pc->column, allow_tabs); } output_to_column(pc->column, allow_tabs); add_text(pc->str); cpd.did_newline = chunk_is_newline(pc); } } }
/** * For a series of lines ending in a comment, align them. * The series ends when more than align_right_cmt_span newlines are found. * * Interesting info: * - least pysically allowed column * - intended column * - least original cmt column * * min_col is the minimum allowed column (based on prev token col/size) * cmt_col less than * * @param start Start point * @return pointer the last item looked at */ chunk_t *align_trailing_comments(chunk_t *start) { int min_col = 0; int min_orig = -1; chunk_t *pc = start; int nl_count = 0; ChunkStack cs; CmtAlignType cmt_type_start, cmt_type_cur; int col; int intended_col = cpd.settings[UO_align_right_cmt_at_col].n; cmt_type_start = get_comment_align_type(pc); LOG_FMT(LALADD, "%s: start on line=%d\n", __func__, pc->orig_line); /* Find the max column */ while ((pc != NULL) && (nl_count < cpd.settings[UO_align_right_cmt_span].n)) { if (((pc->flags & PCF_RIGHT_COMMENT) != 0) && (pc->column > 1)) { cmt_type_cur = get_comment_align_type(pc); if (cmt_type_cur == cmt_type_start) { col = 1 + (pc->brace_level * cpd.settings[UO_indent_columns].n); LOG_FMT(LALADD, "%s: line=%d col=%d max_col=%d pc->col=%d pc->len=%d %s\n", __func__, pc->orig_line, col, min_col, pc->column, pc->len, get_token_name(pc->type)); if ((min_orig < 0) || (min_orig > pc->column)) { min_orig = pc->column; } if (pc->column < col) { pc->column = col; } align_add(cs, pc, min_col, 1, true);//(intended_col < col)); nl_count = 0; } } if (chunk_is_newline(pc)) { nl_count += pc->nl_count; } pc = chunk_get_next(pc); } /* Start with the minimum original column */ col = min_orig; /* fall back to the intended column */ if ((intended_col > 0) && (col > intended_col)) { col = intended_col; } /* if less than allowed, bump it out */ if (col < min_col) { col = min_col; } /* bump out to the intended column */ if (col < intended_col) { col = intended_col; } LOG_FMT(LALADD, "%s: -- min_orig=%d intend=%d min_allowed=%d ==> col=%d\n", __func__, min_orig, intended_col, min_col, col); align_stack(cs, col, (intended_col != 0), LALTC); return(chunk_get_next(pc)); }
/* * See also it's preprocessor counterpart * add_long_closebrace_comment * in braces.cpp * * Note: since this concerns itself with the preprocessor -- which is line-oriented -- * it turns out that just looking at pc->pp_level is NOT the right thing to do. * See a --parsed dump if you don't believe this: an '#endif' will be one level * UP from the corresponding #ifdef when you look at the tokens 'ifdef' versus 'endif', * but it's a whole another story when you look at their CT_PREPROC ('#') tokens! * * Hence we need to track and seek matching CT_PREPROC pp_levels here, which complicates * things a little bit, but not much. */ void add_long_preprocessor_conditional_block_comment(void) { chunk_t *pc; chunk_t *tmp; chunk_t *br_open; chunk_t *br_close; chunk_t *pp_start = NULL; chunk_t *pp_end = NULL; int nl_count; for (pc = chunk_get_head(); pc; pc = chunk_get_next_ncnl(pc)) { /* just track the preproc level: */ if (pc->type == CT_PREPROC) { pp_end = pp_start = pc; } if (pc->type != CT_PP_IF) { continue; } #if 0 if ((pc->flags & PCF_IN_PREPROC) != 0) { continue; } #endif br_open = pc; nl_count = 0; tmp = pc; while ((tmp = chunk_get_next(tmp)) != NULL) { /* just track the preproc level: */ if (tmp->type == CT_PREPROC) { pp_end = tmp; } if (chunk_is_newline(tmp)) { nl_count += tmp->nl_count; } else if ((pp_end->pp_level == pp_start->pp_level) && ((tmp->type == CT_PP_ENDIF) || (br_open->type == CT_PP_IF ? tmp->type == CT_PP_ELSE : 0))) { br_close = tmp; LOG_FMT(LPPIF, "found #if / %s section on lines %d and %d, nl_count=%d\n", (tmp->type == CT_PP_ENDIF ? "#endif" : "#else"), br_open->orig_line, br_close->orig_line, nl_count); /* Found the matching #else or #endif - make sure a newline is next */ tmp = chunk_get_next(tmp); LOG_FMT(LPPIF, "next item type %d (is %s)\n", (tmp ? tmp->type : -1), (tmp ? chunk_is_newline(tmp) ? "newline" : chunk_is_comment(tmp) ? "comment" : "other" : "---")); if ((tmp == NULL) || (tmp->type == CT_NEWLINE) /* chunk_is_newline(tmp) */) { int nl_min; if (br_close->type == CT_PP_ENDIF) { nl_min = cpd.settings[UO_mod_add_long_ifdef_endif_comment].n; } else { nl_min = cpd.settings[UO_mod_add_long_ifdef_else_comment].n; } const char *txt = !tmp ? "EOF" : ((tmp->type == CT_PP_ENDIF) ? "#endif" : "#else"); LOG_FMT(LPPIF, "#if / %s section candidate for augmenting when over NL threshold %d != 0 (nl_count=%d)\n", txt, nl_min, nl_count); if ((nl_min > 0) && (nl_count > nl_min)) /* nl_count is 1 too large at all times as #if line was counted too */ { /* determine the added comment style */ c_token_t style = (cpd.lang_flags & (LANG_CPP | LANG_CS)) ? CT_COMMENT_CPP : CT_COMMENT; unc_text str; generate_if_conditional_as_text(str, br_open); LOG_FMT(LPPIF, "#if / %s section over threshold %d (nl_count=%d) --> insert comment after the %s: %s\n", txt, nl_min, nl_count, txt, str.c_str()); /* Add a comment after the close brace */ insert_comment_after(br_close, style, str); } } /* checks both the #else and #endif for a given level, only then look further in the main loop */ if (br_close->type == CT_PP_ENDIF) { break; } } } } }
/** * Removes superfluous semicolons: * - after brace close whose parent is IF, ELSE, SWITCH, WHILE, FOR, NAMESPACE * - after another semicolon where parent is not FOR * - (D) after brace close whose parent is ENUM/STRUCT/UNION * - after an open brace * - when not in a #DEFINE */ void remove_extra_semicolons(void) { LOG_FUNC_ENTRY(); chunk_t *pc; chunk_t *next; chunk_t *prev; pc = chunk_get_head(); while (pc != NULL) { next = chunk_get_next_ncnl(pc); if ((pc->type == CT_SEMICOLON) && !(pc->flags & PCF_IN_PREPROC) && ((prev = chunk_get_prev_ncnl(pc)) != NULL)) { LOG_FMT(LSCANSEMI, "Semi on %d:%d parent=%s, prev = '%s' [%s/%s]\n", pc->orig_line, pc->orig_col, get_token_name(pc->parent_type), prev->str.c_str(), get_token_name(prev->type), get_token_name(prev->parent_type)); if (pc->parent_type == CT_TYPEDEF) { /* keep it */ } else if ((prev->type == CT_BRACE_CLOSE) && ((prev->parent_type == CT_IF) || (prev->parent_type == CT_ELSEIF) || (prev->parent_type == CT_ELSE) || (prev->parent_type == CT_SWITCH) || (prev->parent_type == CT_WHILE) || (prev->parent_type == CT_USING_STMT) || (prev->parent_type == CT_FOR) || (prev->parent_type == CT_FUNC_DEF) || (prev->parent_type == CT_OC_MSG_DECL) || (prev->parent_type == CT_FUNC_CLASS_DEF) || (prev->parent_type == CT_NAMESPACE))) { LOG_FUNC_CALL(); remove_semicolon(pc); } else if ((prev->type == CT_BRACE_CLOSE) && (prev->parent_type == CT_NONE)) { check_unknown_brace_close(pc, prev); } else if ((prev->type == CT_SEMICOLON) && (prev->parent_type != CT_FOR)) { LOG_FUNC_CALL(); remove_semicolon(pc); } else if ((cpd.lang_flags & LANG_D) && ((prev->parent_type == CT_ENUM) || (prev->parent_type == CT_UNION) || (prev->parent_type == CT_STRUCT))) { LOG_FUNC_CALL(); remove_semicolon(pc); } else if (prev->type == CT_BRACE_OPEN) { LOG_FUNC_CALL(); remove_semicolon(pc); } } pc = next; } }
/** * Adds an entry to the appropriate stack. * * @param pc The chunk * @param seqnum Optional seqnum (0=assign one) */ void AlignStack::Add(chunk_t *start, int seqnum) { LOG_FUNC_ENTRY(); /* Assign a seqnum if needed */ if (seqnum == 0) { seqnum = m_seqnum; } chunk_t *ali; chunk_t *ref; chunk_t *tmp; chunk_t *prev; chunk_t *next; int col_adj = 0; /* Amount the column is shifted for 'dangle' mode */ int tmp_col; int endcol; int gap; m_last_added = 0; /* Check threshold limits */ if ((m_max_col == 0) || (m_thresh == 0) || (((start->column + m_gap) <= (m_max_col + m_thresh)) && (((start->column + m_gap) >= (m_max_col - m_thresh)) || (start->column >= m_min_col)))) { /* we are adding it, so update the newline seqnum */ if (seqnum > m_nl_seqnum) { m_nl_seqnum = seqnum; } /** * SS_IGNORE: no special handling of '*' or '&', only 'foo' is aligned * void foo; // gap=5, 'foo' is aligned * char * foo; // gap=3, 'foo' is aligned * foomatic foo; // gap=1, 'foo' is aligned * The gap is the columns between 'foo' and the previous token. * [void - foo], ['*' - foo], etc * * SS_INCLUDE: - space between variable and '*' or '&' is eaten * void foo; // gap=5, 'foo' is aligned * char *foo; // gap=5, '*' is aligned * foomatic foo; // gap=1, 'foo' is aligned * The gap is the columns between the first '*' or '&' before foo * and the previous token. [void - foo], [char - '*'], etc * * SS_DANGLE: - space between variable and '*' or '&' is eaten * void foo; // gap=5 * char *bar; // gap=5, as the '*' doesn't count * foomatic foo; // gap=1 * The gap is the columns between 'foo' and the chunk before the first * '*' or '&'. [void - foo], [char - bar], etc * * If the gap < m_gap, then the column is bumped out by the difference. * So, if m_gap is 2, then the above would be: * SS_IGNORE: * void foo; // gap=6 * char * foo; // gap=4 * foomatic foo; // gap=2 * SS_INCLUDE: * void foo; // gap=6 * char *foo; // gap=6 * foomatic foo; // gap=2 * SS_DANGLE: * void foo; // gap=6 * char *bar; // gap=6, as the '*' doesn't count * foomatic foo; // gap=2 * Right aligned numbers: * #define A -1 * #define B 631 * #define C 3 * Left aligned numbers: * #define A -1 * #define B 631 * #define C 3 * * In the code below, pc is set to the item that is aligned. * In the above examples, that is 'foo', '*', '-', or 63. * * Ref is set to the last part of the type. * In the above examples, that is 'void', 'char', 'foomatic', 'A', or 'B'. * * The '*' and '&' can float between the two. * * If align_on_tabstop=true, then SS_DANGLE is changed to SS_INCLUDE. */ if (cpd.settings[UO_align_on_tabstop].b && (m_star_style == SS_DANGLE)) { m_star_style = SS_INCLUDE; } /* Find ref. Back up to the real item that is aligned. */ prev = start; while (((prev = chunk_get_prev(prev)) != NULL) && (chunk_is_ptr_operator(prev) || (prev->type == CT_TPAREN_OPEN))) { /* do nothing - we want prev when this exits */ } ref = prev; if (chunk_is_newline(ref)) { ref = chunk_get_next(ref); } /* Find the item that we are going to align. */ ali = start; if (m_star_style != SS_IGNORE) { /* back up to the first '*' or '^' preceding the token */ prev = chunk_get_prev(ali); while (chunk_is_star(prev) || chunk_is_msref(prev)) { ali = prev; prev = chunk_get_prev(ali); } if (chunk_is_token(prev, CT_TPAREN_OPEN)) { ali = prev; prev = chunk_get_prev(ali); // this is correct, even Coverity says: // CID 76021 (#1 of 1): Unused value (UNUSED_VALUE)returned_pointer: Assigning value from // chunk_get_prev(ali, CNAV_ALL) to prev here, but that stored value is overwritten before it can be used. } } if (m_amp_style != SS_IGNORE) { /* back up to the first '&' preceding the token */ prev = chunk_get_prev(ali); while (chunk_is_addr(prev)) { ali = prev; prev = chunk_get_prev(ali); } } /* Tighten down the spacing between ref and start */ if (!cpd.settings[UO_align_keep_extra_space].b) { tmp_col = ref->column; tmp = ref; while (tmp != start) { next = chunk_get_next(tmp); tmp_col += space_col_align(tmp, next); if (next->column != tmp_col) { align_to_column(next, tmp_col); } tmp = next; } } /* Set the column adjust and gap */ col_adj = 0; gap = 0; if (ref != ali) { gap = ali->column - (ref->column + ref->len()); } tmp = ali; if (chunk_is_token(tmp, CT_TPAREN_OPEN)) { tmp = chunk_get_next(tmp); } if ((chunk_is_star(tmp) && (m_star_style == SS_DANGLE)) || (chunk_is_addr(tmp) && (m_amp_style == SS_DANGLE)) || (chunk_is_msref(tmp) && (m_star_style == SS_DANGLE))) // TODO: add m_msref_style { col_adj = start->column - ali->column; gap = start->column - (ref->column + ref->len()); } /* See if this pushes out the max_col */ endcol = ali->column + col_adj; if (gap < m_gap) { endcol += m_gap - gap; } // LOG_FMT(LSYS, "[%p] line %d pc='%s' [%s] col:%d ali='%s' [%s] col:%d ref='%s' [%s] col:%d col_adj=%d endcol=%d, ss=%d as=%d, gap=%d\n", // this, // start->orig_line, // start->text(), get_token_name(start->type), start->column, // ali->text(), get_token_name(ali->type), ali->column, // ref->text(), get_token_name(ref->type), ref->column, // col_adj, endcol, m_star_style, m_amp_style, gap); ali->align.col_adj = col_adj; ali->align.ref = ref; ali->align.start = start; m_aligned.Push_Back(ali, seqnum); m_last_added = 1; LOG_FMT(LAS, "Add-[%s]: line %lu, col %d, adj %d : ref=[%s] endcol=%d\n", ali->text(), ali->orig_line, ali->column, ali->align.col_adj, ref->text(), endcol); if (m_min_col > endcol) { m_min_col = endcol; } if (endcol > m_max_col) { LOG_FMT(LAS, "Add-aligned [%d/%d/%d]: line %lu, col %d : max_col old %d, new %d - min_col %d\n", seqnum, m_nl_seqnum, m_seqnum, ali->orig_line, ali->column, m_max_col, endcol, m_min_col); m_max_col = endcol; /** * If there were any entries that were skipped, re-add them as they * may now be within the threshold */ if (!m_skipped.Empty()) { ReAddSkipped(); } } else { LOG_FMT(LAS, "Add-aligned [%d/%d/%d]: line %lu, col %d : col %d <= %d - min_col %d\n", seqnum, m_nl_seqnum, m_seqnum, ali->orig_line, ali->column, endcol, m_max_col, m_min_col); } } else { /* The threshold check failed, so add it to the skipped list */ m_skipped.Push_Back(start, seqnum); m_last_added = 2; LOG_FMT(LAS, "Add-skipped [%d/%d/%d]: line %lu, col %d <= %d + %d\n", seqnum, m_nl_seqnum, m_seqnum, start->orig_line, start->column, m_max_col, m_thresh); } } // AlignStack::Add
/** * Figures out where to split a function def/proto/call * * For fcn protos and defs. Also fcn calls where level == brace_level: * - find the open fparen * + if it doesn't have a newline right after it * * see if all parameters will fit individually after the paren * * if not, throw a newline after the open paren & return * - scan backwards to the open fparen or comma * + if there isn't a newline after that item, add one & return * + otherwise, add a newline before the start token * * @param start the offending token * @return the token that should have a newline * inserted before it */ static void split_fcn_params(chunk_t *start) { LOG_FMT(LSPLIT, " %s: ", __func__); chunk_t *next; chunk_t *prev; chunk_t *fpo; chunk_t *pc; /* Find the opening fparen */ fpo = start; while (((fpo = chunk_get_prev(fpo)) != NULL) && (fpo->type != CT_FPAREN_OPEN)) { /* do nothing */ } pc = chunk_get_next(fpo); if (!chunk_is_newline(pc)) { int min_col = pc->column; int max_width = 0; int cur_width = 0; int last_col = -1; LOG_FMT(LSPLIT, " mincol=%d, max_width=%d ", min_col, cpd.settings[UO_code_width].n - min_col); while (pc != NULL) { if (chunk_is_newline(pc)) { last_col = -1; } else { if (last_col < 0) { last_col = pc->column; } cur_width += (pc->column - last_col) + pc->len(); last_col = pc->column + pc->len(); if ((pc->type == CT_COMMA) || (pc->type == CT_FPAREN_CLOSE)) { cur_width--; LOG_FMT(LSPLIT, " width=%d ", cur_width); if (cur_width > max_width) { max_width = cur_width; if ((max_width + min_col) > cpd.settings[UO_code_width].n) { break; } } cur_width = 0; last_col = -1; if (pc->type == CT_FPAREN_CLOSE) { break; } } } pc = chunk_get_next(pc); } // don't split function w/o parameters next = chunk_get_next(fpo); if (((max_width + min_col) > cpd.settings[UO_code_width].n) && next->type != CT_FPAREN_CLOSE) { LOG_FMT(LSPLIT, " - A param won't fit, nl after open paren."); split_before_chunk(chunk_get_next(fpo)); return; } } /* back up until the prev is a comma */ prev = pc; while ((prev = chunk_get_prev(prev)) != NULL) { if (chunk_is_newline(prev) || (prev->type == CT_COMMA)) { break; } if (prev->type == CT_FPAREN_OPEN) { /* Don't split "()" */ pc = chunk_get_next(prev); if (pc->type != c_token_t(prev->type + 1)) { break; } } } if (prev != NULL) { LOG_FMT(LSPLIT, " -- ended on [%s] -- ", get_token_name(prev->type)); } if (prev != NULL) { split_before_chunk(chunk_get_next(prev)); } }
void align_right_comments(void) { chunk_t *pc; chunk_t *prev; bool skip; for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc)) { if ((pc->type == CT_COMMENT) || (pc->type == CT_COMMENT_CPP) || (pc->type == CT_COMMENT_MULTI)) { skip = false; if (pc->parent_type == CT_COMMENT_END) { prev = chunk_get_prev(pc); if (pc->orig_col < (prev->orig_col_end + cpd.settings[UO_align_right_cmt_gap].n)) { LOG_FMT(LALTC, "NOT changing END comment on line %d (%d <= %d + %d)\n", pc->orig_line, pc->orig_col, prev->orig_col_end, cpd.settings[UO_align_right_cmt_gap].n); skip = true; } if (!skip) { LOG_FMT(LALTC, "Changing END comment on line %d into a RIGHT-comment\n", pc->orig_line); pc->flags |= PCF_RIGHT_COMMENT; } } /* Change certain WHOLE comments into RIGHT-alignable comments */ if (pc->parent_type == CT_COMMENT_WHOLE) { int max_col = pc->column_indent + cpd.settings[UO_input_tab_size].n; /* If the comment is further right than the brace level... */ if (pc->column >= max_col) { LOG_FMT(LALTC, "Changing WHOLE comment on line %d into a RIGHT-comment (col=%d col_ind=%d max_col=%d)\n", pc->orig_line, pc->column, pc->column_indent, max_col); pc->flags |= PCF_RIGHT_COMMENT; } } } } pc = chunk_get_head(); while (pc != NULL) { if ((pc->flags & PCF_RIGHT_COMMENT) != 0) { pc = align_trailing_comments(pc); } else { pc = chunk_get_next(pc); } } }
/** * Checks to see if the braces can be removed. * - less than a certain length * - doesn't mess up if/else stuff */ static bool can_remove_braces(chunk_t *bopen) { chunk_t *pc; chunk_t *prev = NULL; int semi_count = 0; int level = bopen->level + 1; bool hit_semi = false; bool was_fcn = false; int nl_max = cpd.settings[UO_mod_full_brace_nl].n; int nl_count = 0; int if_count = 0; int br_count = 0; /* Cannot remove braces inside a preprocessor */ if (bopen->flags & PCF_IN_PREPROC) { return(false); } pc = chunk_get_next_ncnl(bopen, CNAV_PREPROC); if ((pc != NULL) && (pc->type == CT_BRACE_CLOSE)) { /* Can't remove empty statement */ return(false); } LOG_FMT(LBRDEL, "%s: start on %d : ", __func__, bopen->orig_line); pc = chunk_get_next_nc(bopen, CNAV_ALL); while ((pc != NULL) && (pc->level >= level)) { if (pc->flags & PCF_IN_PREPROC) { /* Cannot remove braces that contain a preprocessor */ return(false); } if (chunk_is_newline(pc)) { nl_count += pc->nl_count; if ((nl_max > 0) && (nl_count > nl_max)) { LOG_FMT(LBRDEL, " exceeded %d newlines\n", nl_max); return(false); } } else { if (pc->type == CT_BRACE_OPEN) { br_count++; } else if (pc->type == CT_BRACE_CLOSE) { br_count--; } else if ((pc->type == CT_IF) || (pc->type == CT_ELSEIF)) { if (br_count == 0) { if_count++; } } if (pc->level == level) { if ((semi_count > 0) && hit_semi) { /* should have bailed due to close brace level drop */ LOG_FMT(LBRDEL, " no close brace\n"); return(false); } LOG_FMT(LBRDEL, " [%s %d-%d]", pc->str.c_str(), pc->orig_line, semi_count); if (pc->type == CT_ELSE) { LOG_FMT(LBRDEL, " bailed on %s on line %d\n", pc->str.c_str(), pc->orig_line); return(false); } was_fcn = (prev != NULL) && (prev->type == CT_FPAREN_CLOSE); if (chunk_is_semicolon(pc) || (pc->type == CT_IF) || (pc->type == CT_ELSEIF) || (pc->type == CT_FOR) || (pc->type == CT_DO) || (pc->type == CT_WHILE) || (pc->type == CT_USING_STMT) || ((pc->type == CT_BRACE_OPEN) && was_fcn)) { hit_semi |= chunk_is_semicolon(pc); if (++semi_count > 1) { LOG_FMT(LBRDEL, " bailed on %d because of %s on line %d\n", bopen->orig_line, pc->str.c_str(), pc->orig_line); return(false); } } } } prev = pc; pc = chunk_get_next_nc(pc); } if (pc == NULL) { LOG_FMT(LBRDEL, " NULL\n"); return(false); } if ((pc->type == CT_BRACE_CLOSE) && (pc->parent_type == CT_IF)) { chunk_t *next = chunk_get_next_ncnl(pc, CNAV_PREPROC); prev = chunk_get_prev_ncnl(pc, CNAV_PREPROC); if ((next != NULL) && (next->type == CT_ELSE) && ((prev->type == CT_BRACE_CLOSE) || (prev->type == CT_VBRACE_CLOSE)) && (prev->parent_type == CT_IF)) { LOG_FMT(LBRDEL, " - bailed on '%s'[%s] on line %d due to 'if' and 'else' sequence\n", get_token_name(pc->type), get_token_name(pc->parent_type), pc->orig_line); return(false); } } LOG_FMT(LBRDEL, " - end on '%s' on line %d. if_count=%d semi_count=%d\n", get_token_name(pc->type), pc->orig_line, if_count, semi_count); return((pc->type == CT_BRACE_CLOSE) && (pc->pp_level == bopen->pp_level)); }
/** * Scans the whole file for #defines. Aligns all within X lines of each other */ void align_preprocessor(void) { chunk_t *pc; AlignStack as; // value macros AlignStack asf; // function macros AlignStack *cur_as = &as; as.Start(cpd.settings[UO_align_pp_define_span].n); as.m_gap = cpd.settings[UO_align_pp_define_gap].n; asf.Start(cpd.settings[UO_align_pp_define_span].n); asf.m_gap = cpd.settings[UO_align_pp_define_gap].n; pc = chunk_get_head(); while (pc != NULL) { /* Note: not counting back-slash newline combos */ if (pc->type == CT_NEWLINE) { as.NewLines(pc->nl_count); asf.NewLines(pc->nl_count); } /* If we aren't on a 'define', then skip to the next non-comment */ if (pc->type != CT_PP_DEFINE) { pc = chunk_get_next_nc(pc); continue; } /* step past the 'define' */ pc = chunk_get_next_nc(pc); if (pc == NULL) { break; } LOG_FMT(LALPP, "%s: define (%.*s) on line %d col %d\n", __func__, pc->len, pc->str, pc->orig_line, pc->orig_col); cur_as = &as; if (pc->type == CT_MACRO_FUNC) { cur_as = &asf; /* Skip to the close paren */ pc = chunk_get_next_nc(pc); // point to open ( pc = chunk_get_next_type(pc, CT_FPAREN_CLOSE, pc->level); LOG_FMT(LALPP, "%s: jumped to (%.*s) on line %d col %d\n", __func__, pc->len, pc->str, pc->orig_line, pc->orig_col); } /* step to the value past the close paren or the macro name */ pc = chunk_get_next(pc); if (pc == NULL) { break; } /* don't align anything if the first line ends with a newline before * a value is given */ if (!chunk_is_newline(pc)) { LOG_FMT(LALPP, "%s: align on '%.*s', line %d col %d\n", __func__, pc->len, pc->str, pc->orig_line, pc->orig_col); cur_as->Add(pc); } } as.End(); asf.End(); }
/** * Add the case brace, if allowable. */ static chunk_t *mod_case_brace_add(chunk_t *cl_colon) { chunk_t *pc = cl_colon; chunk_t *last = NULL; chunk_t *next = chunk_get_next_ncnl(cl_colon, CNAV_PREPROC); chunk_t *br_open; chunk_t *br_close; chunk_t chunk; LOG_FMT(LMCB, "%s: line %d", __func__, pc->orig_line); while ((pc = chunk_get_next_ncnl(pc, CNAV_PREPROC)) != NULL) { if (pc->level < cl_colon->level) { LOG_FMT(LMCB, " - level drop\n"); return(next); } if ((pc->level == cl_colon->level) && ((pc->type == CT_CASE) || (pc->type == CT_BREAK))) { last = pc; //if (pc->type == CT_BREAK) //{ // /* Step past the semicolon */ // last = chunk_get_next_ncnl(chunk_get_next_ncnl(last)); //} break; } } if (last == NULL) { LOG_FMT(LMCB, " - NULL last\n"); return(next); } LOG_FMT(LMCB, " - adding before '%s' on line %d\n", last->str.c_str(), last->orig_line); chunk.type = CT_BRACE_OPEN; chunk.orig_line = cl_colon->orig_line; chunk.parent_type = CT_CASE; chunk.level = cl_colon->level; chunk.brace_level = cl_colon->brace_level; chunk.flags = pc->flags & PCF_COPY_FLAGS; chunk.str = "{"; br_open = chunk_add_after(&chunk, cl_colon); chunk.type = CT_BRACE_CLOSE; chunk.orig_line = last->orig_line; chunk.str = "}"; br_close = chunk_add_before(&chunk, last); newline_add_before(last); for (pc = chunk_get_next(br_open, CNAV_PREPROC); pc != br_close; pc = chunk_get_next(pc, CNAV_PREPROC)) { pc->level++; pc->brace_level++; } return(br_open); }
/** * Aligns all assignment operators on the same level as first, starting with * first. * * For variable definitions, only consider the '=' for the first variable. * Otherwise, only look at the first '=' on the line. */ chunk_t *align_assign(chunk_t *first, int span, int thresh) { int my_level; chunk_t *pc; int tmp; int var_def_cnt = 0; int equ_count = 0; if (first == NULL) { return(NULL); } my_level = first->level; if (span <= 0) { return(chunk_get_next(first)); } LOG_FMT(LALASS, "%s[%d]: checking %.*s on line %d - span=%d thresh=%d\n", __func__, my_level, first->len, first->str, first->orig_line, span, thresh); AlignStack as; // regular assigns AlignStack vdas; // variable def assigns as.Start(span, thresh); as.m_right_align = true; vdas.Start(span, thresh); vdas.m_right_align = true; pc = first; while ((pc != NULL) && ((pc->level >= my_level) || (pc->level == 0))) { /* Don't check inside PAREN or SQUARE groups */ if ((pc->type == CT_SPAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SQUARE_OPEN) || (pc->type == CT_PAREN_OPEN)) { tmp = pc->orig_line; pc = chunk_skip_to_match(pc); if (pc != NULL) { as.NewLines(pc->orig_line - tmp); vdas.NewLines(pc->orig_line - tmp); } continue; } /* Recurse if a brace set is found */ if ((pc->type == CT_BRACE_OPEN) || (pc->type == CT_VBRACE_OPEN)) { int myspan; int mythresh; tmp = pc->orig_line; if (pc->parent_type == CT_ENUM) { myspan = cpd.settings[UO_align_enum_equ_span].n; mythresh = cpd.settings[UO_align_enum_equ_thresh].n; } else { myspan = cpd.settings[UO_align_assign_span].n; mythresh = cpd.settings[UO_align_assign_thresh].n; } pc = align_assign(chunk_get_next_ncnl(pc), myspan, mythresh); if (pc != NULL) { /* do a rough count of the number of lines just spanned */ as.NewLines(pc->orig_line - tmp); vdas.NewLines(pc->orig_line - tmp); } continue; } if (chunk_is_newline(pc)) { as.NewLines(pc->nl_count); vdas.NewLines(pc->nl_count); var_def_cnt = 0; equ_count = 0; } else if ((pc->flags & PCF_VAR_DEF) != 0) { var_def_cnt++; } else if (var_def_cnt > 1) { /* we hit the second variable def - don't look for assigns */ } else if ((equ_count == 0) && (pc->type == CT_ASSIGN)) { //fprintf(stderr, "%s: ** %s level=%d line=%d col=%d prev=%d count=%d\n", // __func__, pc->str, pc->level, pc->orig_line, pc->orig_col, prev_equ_type, // equ_count); equ_count++; if (var_def_cnt != 0) { vdas.Add(pc); } else { as.Add(pc); } } pc = chunk_get_next(pc); } as.End(); vdas.End(); if (pc != NULL) { LOG_FMT(LALASS, "%s: done on %.*s on line %d\n", __func__, pc->len, pc->str, pc->orig_line); } else { LOG_FMT(LALASS, "%s: done on NULL\n", __func__); } return(pc); }
static void uncrustify_file(const file_mem& fm, FILE *pfout, const char *parsed_file) { const deque<int>& data = fm.data; /* Save off the encoding and whether a BOM is required */ cpd.bom = fm.bom; cpd.enc = fm.enc; if (cpd.settings[UO_utf8_force].b || ((cpd.enc == ENC_BYTE) && cpd.settings[UO_utf8_byte].b)) { cpd.enc = ENC_UTF8; } argval_t av; switch (cpd.enc) { case ENC_UTF8: av = cpd.settings[UO_utf8_bom].a; break; case ENC_UTF16_LE: case ENC_UTF16_BE: av = AV_FORCE; break; default: av = AV_IGNORE; break; } if (av == AV_REMOVE) { cpd.bom = false; } else if (av != AV_IGNORE) { cpd.bom = true; } /* Check for embedded 0's (represents a decoding failure or corrupt file) */ for (int idx = 0; idx < (int)data.size() - 1; idx++) { if (data[idx] == 0) { LOG_FMT(LERR, "An embedded 0 was found in '%s'.\n", cpd.filename); LOG_FMT(LERR, "The file may be encoded in an unsupported Unicode format.\n"); LOG_FMT(LERR, "Aborting.\n"); cpd.error_count++; return; } } uncrustify_start(data); /** * Done with detection. Do the rest only if the file will go somewhere. * The detection code needs as few changes as possible. */ if (pfout != NULL) { /** * Add comments before function defs and classes */ if (cpd.func_hdr.data.size() > 0) { add_func_header(CT_FUNC_DEF, cpd.func_hdr); } if (cpd.class_hdr.data.size() > 0) { add_func_header(CT_CLASS, cpd.class_hdr); } if (cpd.oc_msg_hdr.data.size() > 0) { add_msg_header(CT_OC_MSG_DECL, cpd.oc_msg_hdr); } /** * Change virtual braces into real braces... */ do_braces(); /* Scrub extra semicolons */ if (cpd.settings[UO_mod_remove_extra_semicolon].b) { remove_extra_semicolons(); } /* Remove unnecessary returns */ if (cpd.settings[UO_mod_remove_empty_return].b) { remove_extra_returns(); } /** * Add parens */ do_parens(); /** * Modify line breaks as needed */ bool first = true; int old_changes; if (cpd.settings[UO_nl_remove_extra_newlines].n == 2) { newlines_remove_newlines(); } cpd.pass_count = 3; do { old_changes = cpd.changes; LOG_FMT(LNEWLINE, "Newline loop start: %d\n", cpd.changes); newlines_cleanup_dup(); newlines_cleanup_braces(first); if (cpd.settings[UO_nl_after_multiline_comment].b) { newline_after_multiline_comment(); } newlines_insert_blank_lines(); if (cpd.settings[UO_pos_bool].tp != TP_IGNORE) { newlines_chunk_pos(CT_BOOL, cpd.settings[UO_pos_bool].tp); } if (cpd.settings[UO_pos_compare].tp != TP_IGNORE) { newlines_chunk_pos(CT_COMPARE, cpd.settings[UO_pos_compare].tp); } if (cpd.settings[UO_pos_conditional].tp != TP_IGNORE) { newlines_chunk_pos(CT_COND_COLON, cpd.settings[UO_pos_conditional].tp); newlines_chunk_pos(CT_QUESTION, cpd.settings[UO_pos_conditional].tp); } if (cpd.settings[UO_pos_comma].tp != TP_IGNORE) { newlines_chunk_pos(CT_COMMA, cpd.settings[UO_pos_comma].tp); } if (cpd.settings[UO_pos_assign].tp != TP_IGNORE) { newlines_chunk_pos(CT_ASSIGN, cpd.settings[UO_pos_assign].tp); } if (cpd.settings[UO_pos_arith].tp != TP_IGNORE) { newlines_chunk_pos(CT_ARITH, cpd.settings[UO_pos_arith].tp); newlines_chunk_pos(CT_CARET, cpd.settings[UO_pos_arith].tp); } newlines_class_colon_pos(); if (cpd.settings[UO_nl_squeeze_ifdef].b) { newlines_squeeze_ifdef(); } do_blank_lines(); newlines_eat_start_end(); newlines_cleanup_dup(); first = false; } while ((old_changes != cpd.changes) && (cpd.pass_count-- > 0)); mark_comments(); /** * Add balanced spaces around nested params */ if (cpd.settings[UO_sp_balance_nested_parens].b) { space_text_balance_nested_parens(); } /* Scrub certain added semicolons */ if (((cpd.lang_flags & LANG_PAWN) != 0) && cpd.settings[UO_mod_pawn_semicolon].b) { pawn_scrub_vsemi(); } /* Sort imports/using/include */ if (cpd.settings[UO_mod_sort_import].b || cpd.settings[UO_mod_sort_include].b || cpd.settings[UO_mod_sort_using].b) { sort_imports(); } /** * Fix same-line inter-chunk spacing */ space_text(); /** * Do any aligning of preprocessors */ if (cpd.settings[UO_align_pp_define_span].n > 0) { align_preprocessor(); } /** * Indent the text */ indent_preproc(); indent_text(); /* Insert trailing comments after certain close braces */ if ((cpd.settings[UO_mod_add_long_switch_closebrace_comment].n > 0) || (cpd.settings[UO_mod_add_long_function_closebrace_comment].n > 0)) { add_long_closebrace_comment(); } /* Insert trailing comments after certain preprocessor conditional blocks */ if ((cpd.settings[UO_mod_add_long_ifdef_else_comment].n > 0) || (cpd.settings[UO_mod_add_long_ifdef_endif_comment].n > 0)) { add_long_preprocessor_conditional_block_comment(); } /** * Align everything else, reindent and break at code_width */ first = true; cpd.pass_count = 3; do { align_all(); indent_text(); old_changes = cpd.changes; if (cpd.settings[UO_code_width].n > 0) { LOG_FMT(LNEWLINE, "Code_width loop start: %d\n", cpd.changes); do_code_width(); if ((old_changes != cpd.changes) && first) { /* retry line breaks caused by splitting 1-liners */ newlines_cleanup_braces(false); newlines_insert_blank_lines(); first = false; } } } while ((old_changes != cpd.changes) && (cpd.pass_count-- > 0)); /** * And finally, align the backslash newline stuff */ align_right_comments(); if (cpd.settings[UO_align_nl_cont].b) { align_backslash_newline(); } /** * Now render it all to the output file */ output_text(pfout); } /* Special hook for dumping parsed data for debugging */ if (parsed_file != NULL) { FILE *p_file = fopen(parsed_file, "w"); if (p_file != NULL) { output_parsed(p_file); fclose(p_file); } else { LOG_FMT(LERR, "%s: Failed to open '%s' for write: %s (%d)\n", __func__, parsed_file, strerror(errno), errno); } } uncrustify_end(); }
static void align_same_func_call_params() { chunk_t *pc; chunk_t *align_root = NULL; chunk_t *align_cur = NULL; int align_len = 0; chunk_t *chunks[16]; AlignStack as[16]; AlignStack fcn_as; int max_idx = -1; int cur_as; int idx; const char *add_str = NULL; fcn_as.Start(3); for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc)) { if (pc->type != CT_FUNC_CALL) { if (chunk_is_newline(pc)) { for (idx = 0; idx <= max_idx; idx++) { as[idx].NewLines(pc->nl_count); } fcn_as.NewLines(pc->nl_count); } continue; } /* Only align function calls that are right after a newline */ if (!chunk_is_newline(chunk_get_prev(pc))) { continue; } fcn_as.Add(pc); add_str = NULL; if (align_root != NULL) { if ((pc->len == align_root->len) && (memcmp(pc->str, align_root->str, pc->len) == 0)) { align_cur->align.next = pc; align_cur = pc; align_len++; add_str = " Add"; } else { LOG_FMT(LASFCP, " ++ Ended with %d fcns\n", align_len); /* Flush it all! */ fcn_as.Flush(); for (idx = 0; idx <= max_idx; idx++) { as[idx].Flush(); } align_root = NULL; } } if (align_root == NULL) { align_root = pc; align_cur = pc; align_len = 1; add_str = "Start"; } if (add_str != NULL) { LOG_FMT(LASFCP, "%s '%.*s' on line %d -", add_str, pc->len, pc->str, pc->orig_line); cur_as = align_params(pc, chunks, ARRAY_SIZE(chunks)); LOG_FMT(LASFCP, " %d items:", cur_as); for (idx = 0; idx < cur_as; idx++) { LOG_FMT(LASFCP, " [%.*s]", chunks[idx]->len, chunks[idx]->str); if (idx > max_idx) { as[idx].Start(3); if (!cpd.settings[UO_align_number_left].b) { if ((chunks[idx]->type == CT_NUMBER_FP) || (chunks[idx]->type == CT_NUMBER) || (chunks[idx]->type == CT_POS) || (chunks[idx]->type == CT_NEG)) { as[idx].m_right_align = true; } } max_idx = idx; } as[idx].Add(chunks[idx]); } LOG_FMT(LASFCP, "\n"); } } fcn_as.End(); for (idx = 0; idx <= max_idx; idx++) { as[idx].End(); } }
/** * Does a source file. * * @param filename_in the file to read * @param filename_out NULL (stdout) or the file to write * @param parsed_file NULL or the filename for the parsed debug info * @param no_backup don't create a backup, if filename_out == filename_in * @param keep_mtime don't change the mtime (dangerous) */ static void do_source_file(const char *filename_in, const char *filename_out, const char *parsed_file, bool no_backup, bool keep_mtime) { FILE *pfout; bool did_open = false; bool need_backup = false; file_mem fm; string filename_tmp; /* Do some simple language detection based on the filename extension */ if (!cpd.lang_forced || (cpd.lang_flags == 0)) { cpd.lang_flags = language_from_filename(filename_in); } /* Try to read in the source file */ if (load_mem_file(filename_in, fm) < 0) { LOG_FMT(LERR, "Failed to load (%s)\n", filename_in); cpd.error_count++; return; } LOG_FMT(LSYS, "Parsing: %s as language %s\n", filename_in, language_to_string(cpd.lang_flags)); if (filename_out == NULL) { pfout = stdout; } else { /* If the out file is the same as the in file, then use a temp file */ filename_tmp = filename_out; if (strcmp(filename_in, filename_out) == 0) { /* Create 'outfile.uncrustify' */ filename_tmp = fix_filename(filename_out); if (!no_backup) { if (backup_copy_file(filename_in, fm.raw) != SUCCESS) { LOG_FMT(LERR, "%s: Failed to create backup file for %s\n", __func__, filename_in); cpd.error_count++; return; } need_backup = true; } } make_folders(filename_tmp); pfout = fopen(filename_tmp.c_str(), "wb"); if (pfout == NULL) { LOG_FMT(LERR, "%s: Unable to create %s: %s (%d)\n", __func__, filename_tmp.c_str(), strerror(errno), errno); cpd.error_count++; return; } did_open = true; //LOG_FMT(LSYS, "Output file %s\n", filename_out); } cpd.filename = filename_in; uncrustify_file(fm, pfout, parsed_file); if (did_open) { fclose(pfout); if (need_backup) { backup_create_md5_file(filename_in); } if (filename_tmp != filename_out) { /* We need to compare and then do a rename */ if (file_content_matches(filename_tmp, filename_out)) { /* No change - remove tmp file */ (void)unlink(filename_tmp.c_str()); } else { #ifdef WIN32 /* windows can't rename a file if the target exists, so delete it * first. This may cause data loss if the tmp file gets deleted * or can't be renamed. */ (void)unlink(filename_out); #endif /* Change - rename filename_tmp to filename_out */ if (rename(filename_tmp.c_str(), filename_out) != 0) { LOG_FMT(LERR, "%s: Unable to rename '%s' to '%s'\n", __func__, filename_tmp.c_str(), filename_out); cpd.error_count++; } } } #ifdef HAVE_UTIME_H if (keep_mtime) { /* update mtime -- don't care if it fails */ fm.utb.actime = time(NULL); (void)utime(filename_in, &fm.utb); } #endif } }
/** * Scan everything at the current level until the close brace and find the * variable def align column. Also aligns bit-colons, but that assumes that * bit-types are the same! But that should always be the case... */ static chunk_t *align_var_def_brace(chunk_t *start, int span, int *p_nl_count) { chunk_t *pc; chunk_t *next; chunk_t *prev; UINT64 align_mask = PCF_IN_FCN_DEF | PCF_VAR_1ST; int myspan = span; int mythresh = 0; int mygap = 0; AlignStack as; /* var/proto/def */ AlignStack as_bc; /* bit-colon */ AlignStack as_at; /* attribute */ AlignStack as_br; /* one-liner brace open */ bool fp_active = cpd.settings[UO_align_mix_var_proto].b; bool fp_look_bro = false; if (start == NULL) { return(NULL); } /* Override the span, if this is a struct/union */ if ((start->parent_type == CT_STRUCT) || (start->parent_type == CT_UNION)) { myspan = cpd.settings[UO_align_var_struct_span].n; mythresh = cpd.settings[UO_align_var_struct_thresh].n; mygap = cpd.settings[UO_align_var_struct_gap].n; } else { mythresh = cpd.settings[UO_align_var_def_thresh].n; mygap = cpd.settings[UO_align_var_def_gap].n; } /* can't be any variable definitions in a "= {" block */ prev = chunk_get_prev_ncnl(start); if ((prev != NULL) && (prev->type == CT_ASSIGN)) { LOG_FMT(LAVDB, "%s: start=%.*s [%s] on line %d (abort due to assign)\n", __func__, start->len, start->str, get_token_name(start->type), start->orig_line); pc = chunk_get_next_type(start, CT_BRACE_CLOSE, start->level); return(chunk_get_next_ncnl(pc)); } LOG_FMT(LAVDB, "%s: start=%.*s [%s] on line %d\n", __func__, start->len, start->str, get_token_name(start->type), start->orig_line); if (!cpd.settings[UO_align_var_def_inline].b) { align_mask |= PCF_VAR_INLINE; } /* Set up the var/proto/def aligner */ as.Start(myspan, mythresh); as.m_gap = mygap; as.m_star_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_star_style].n; as.m_amp_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_amp_style].n; /* Set up the bit colon aligner */ as_bc.Start(myspan, 0); as_bc.m_gap = cpd.settings[UO_align_var_def_colon_gap].n; as_at.Start(myspan, 0); /* Set up the brace open aligner */ as_br.Start(myspan, mythresh); as_br.m_gap = cpd.settings[UO_align_single_line_brace_gap].n; bool did_this_line = false; pc = chunk_get_next(start); while ((pc != NULL) && ((pc->level >= start->level) || (pc->level == 0))) { if (chunk_is_comment(pc)) { if (pc->nl_count > 0) { as.NewLines(pc->nl_count); as_bc.NewLines(pc->nl_count); as_at.NewLines(pc->nl_count); as_br.NewLines(pc->nl_count); } pc = chunk_get_next(pc); continue; } if (fp_active) { if ((pc->type == CT_FUNC_PROTO) || ((pc->type == CT_FUNC_DEF) && cpd.settings[UO_align_single_line_func].b)) { LOG_FMT(LAVDB, " add=[%.*s] line=%d col=%d level=%d\n", pc->len, pc->str, pc->orig_line, pc->orig_col, pc->level); as.Add(pc); fp_look_bro = (pc->type == CT_FUNC_DEF) && cpd.settings[UO_align_single_line_brace].b; } else if (fp_look_bro && (pc->type == CT_BRACE_OPEN) && (pc->flags & PCF_ONE_LINER)) { as_br.Add(pc); fp_look_bro = false; } } /* process nested braces */ if (pc->type == CT_BRACE_OPEN) { int sub_nl_count = 0; pc = align_var_def_brace(pc, span, &sub_nl_count); if (sub_nl_count > 0) { fp_look_bro = false; did_this_line = false; as.NewLines(sub_nl_count); as_bc.NewLines(sub_nl_count); as_at.NewLines(sub_nl_count); as_br.NewLines(sub_nl_count); if (p_nl_count != NULL) { *p_nl_count += sub_nl_count; } } continue; } /* Done with this brace set? */ if (pc->type == CT_BRACE_CLOSE) { pc = chunk_get_next(pc); break; } if (chunk_is_newline(pc)) { fp_look_bro = false; did_this_line = false; as.NewLines(pc->nl_count); as_bc.NewLines(pc->nl_count); as_at.NewLines(pc->nl_count); as_br.NewLines(pc->nl_count); if (p_nl_count != NULL) { *p_nl_count += pc->nl_count; } } /* don't align stuff inside parens/squares/angles */ if (pc->level > pc->brace_level) { pc = chunk_get_next(pc); continue; } /* If this is a variable def, update the max_col */ if ((pc->type != CT_FUNC_CLASS) && ((pc->flags & align_mask) == PCF_VAR_1ST) && ((pc->level == (start->level + 1)) || (pc->level == 0))) { if (!did_this_line) { LOG_FMT(LAVDB, " add=[%.*s] line=%d col=%d level=%d\n", pc->len, pc->str, pc->orig_line, pc->orig_col, pc->level); as.Add(pc); if (cpd.settings[UO_align_var_def_colon].b) { next = chunk_get_next_nc(pc); if (next->type == CT_BIT_COLON) { as_bc.Add(next); } } if (cpd.settings[UO_align_var_def_attribute].b) { next = pc; while ((next = chunk_get_next_nc(next)) != NULL) { if (next->type == CT_ATTRIBUTE) { as_at.Add(next); break; } if ((next->type == CT_SEMICOLON) || chunk_is_newline(next)) { break; } } } } did_this_line = true; } else if (pc->type == CT_BIT_COLON) { if (!did_this_line) { as_bc.Add(pc); did_this_line = true; } } pc = chunk_get_next(pc); } as.End(); as_bc.End(); as_at.End(); as_br.End(); return(pc); }
/** * At the heart of this algorithm are two stacks. * There is the Paren Stack (PS) and the Frame stack. * * The PS (pse in the code) keeps track of braces, parens, * if/else/switch/do/while/etc items -- anything that is nestable. * Complex statements go through stages. * Take this simple if statement as an example: * if ( x ) { x--; } * * The stack would change like so: 'token' stack afterwards * 'if' [IF - 1] * '(' [IF - 1] [PAREN OPEN] * 'x' [IF - 1] [PAREN OPEN] * ')' [IF - 2] <- note that the state was incremented * '{' [IF - 2] [BRACE OPEN] * 'x' [IF - 2] [BRACE OPEN] * '--' [IF - 2] [BRACE OPEN] * ';' [IF - 2] [BRACE OPEN] * '}' [IF - 3] * <- lack of else kills the IF, closes statement * * Virtual braces example: * if ( x ) x--; else x++; * * 'if' [IF - 1] * '(' [IF - 1] [PAREN OPEN] * 'x' [IF - 1] [PAREN OPEN] * ')' [IF - 2] * 'x' [IF - 2] [VBRACE OPEN] <- VBrace open inserted before because '{' was not next * '--' [IF - 2] [VBRACE OPEN] * ';' [IF - 3] <- VBrace close inserted after semicolon * 'else' [ELSE - 0] <- IF changed into ELSE * 'x' [ELSE - 0] [VBRACE OPEN] <- lack of '{' -> VBrace * '++' [ELSE - 0] [VBRACE OPEN] * ';' [ELSE - 0] <- VBrace close inserted after semicolon * <- ELSE removed after statement close * * The pse stack is kept on a frame stack. * The frame stack is need for languages that support preprocessors (C, C++, C#) * that can arbitrarily change code flow. It also isolates #define macros so * that they are indented independently and do not affect the rest of the program. * * When an #if is hit, a copy of the current frame is push on the frame stack. * When an #else/#elif is hit, a copy of the current stack is pushed under the * #if frame and the original (pre-#if) frame is copied to the current frame. * When #endif is hit, the top frame is popped. * This has the following effects: * - a simple #if / #endif does not affect program flow * - #if / #else /#endif - continues from the #if clause * * When a #define is entered, the current frame is pushed and cleared. * When a #define is exited, the frame is popped. */ static void parse_cleanup(struct parse_frame *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); c_token_t parent = CT_NONE; chunk_t *prev; LOG_FMT(LTOK, "%s:%d] %16s - tos:%d/%16s stg:%d\n", __func__, pc->orig_line, get_token_name(pc->type), frm->pse_tos, get_token_name(frm->pse[frm->pse_tos].type), frm->pse[frm->pse_tos].stage); /* Mark statement starts */ if (((frm->stmt_count == 0) || (frm->expr_count == 0)) && !chunk_is_semicolon(pc) && (pc->type != CT_BRACE_CLOSE) && (pc->type != CT_VBRACE_CLOSE) && !chunk_is_str(pc, ")", 1) && !chunk_is_str(pc, "]", 1)) { chunk_flags_set(pc, PCF_EXPR_START | ((frm->stmt_count == 0) ? PCF_STMT_START : 0)); LOG_FMT(LSTMT, "%d] 1.marked %s as %s start st:%d ex:%d\n", pc->orig_line, pc->text(), (pc->flags & PCF_STMT_START) ? "stmt" : "expr", frm->stmt_count, frm->expr_count); } frm->stmt_count++; frm->expr_count++; if (frm->sparen_count > 0) { int tmp; chunk_flags_set(pc, PCF_IN_SPAREN); /* Mark everything in the a for statement */ for (tmp = frm->pse_tos - 1; tmp >= 0; tmp--) { if (frm->pse[tmp].type == CT_FOR) { chunk_flags_set(pc, PCF_IN_FOR); break; } } /* Mark the parent on semicolons in for() stmts */ if ((pc->type == CT_SEMICOLON) && (frm->pse_tos > 1) && (frm->pse[frm->pse_tos - 1].type == CT_FOR)) { set_chunk_parent(pc, CT_FOR); } } /* Check the progression of complex statements */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { if (check_complex_statements(frm, pc)) { return; } } /** * Check for a virtual brace statement close due to a semicolon. * The virtual brace will get handled the next time through. * The semicolon isn't handled at all. * TODO: may need to float VBRACE past comments until newline? */ if (frm->pse[frm->pse_tos].type == CT_VBRACE_OPEN) { if (chunk_is_semicolon(pc)) { cpd.consumed = true; close_statement(frm, pc); } else if (cpd.lang_flags & LANG_PAWN) { if (pc->type == CT_BRACE_CLOSE) { close_statement(frm, pc); } } } /* Handle close paren, vbrace, brace, and square */ if ((pc->type == CT_PAREN_CLOSE) || (pc->type == CT_BRACE_CLOSE) || (pc->type == CT_VBRACE_CLOSE) || (pc->type == CT_ANGLE_CLOSE) || (pc->type == CT_MACRO_CLOSE) || (pc->type == CT_SQUARE_CLOSE)) { /* Change CT_PAREN_CLOSE into CT_SPAREN_CLOSE or CT_FPAREN_CLOSE */ if ((pc->type == CT_PAREN_CLOSE) && ((frm->pse[frm->pse_tos].type == CT_FPAREN_OPEN) || (frm->pse[frm->pse_tos].type == CT_SPAREN_OPEN))) { set_chunk_type(pc, (c_token_t)(frm->pse[frm->pse_tos].type + 1)); if (pc->type == CT_SPAREN_CLOSE) { frm->sparen_count--; chunk_flags_clr(pc, PCF_IN_SPAREN); } } /* Make sure the open / close match */ if (pc->type != (frm->pse[frm->pse_tos].type + 1)) { if ((frm->pse[frm->pse_tos].type != CT_NONE) && (frm->pse[frm->pse_tos].type != CT_PP_DEFINE)) { LOG_FMT(LWARN, "%s:%d Error: Unexpected '%s' for '%s', which was on line %d\n", cpd.filename, pc->orig_line, pc->text(), get_token_name(frm->pse[frm->pse_tos].pc->type), frm->pse[frm->pse_tos].pc->orig_line); print_stack(LBCSPOP, "=Error ", frm, pc); cpd.error_count++; } } else { cpd.consumed = true; /* Copy the parent, update the paren/brace levels */ set_chunk_parent(pc, frm->pse[frm->pse_tos].parent); frm->level--; if ((pc->type == CT_BRACE_CLOSE) || (pc->type == CT_VBRACE_CLOSE) || (pc->type == CT_MACRO_CLOSE)) { frm->brace_level--; } pc->level = frm->level; pc->brace_level = frm->brace_level; /* Pop the entry */ frm->pse_tos--; print_stack(LBCSPOP, "-Close ", frm, pc); /* See if we are in a complex statement */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { handle_complex_close(frm, pc); } } } /* In this state, we expect a semicolon, but we'll also hit the closing * sparen, so we need to check cpd.consumed to see if the close sparen was * aleady handled. */ if (frm->pse[frm->pse_tos].stage == BS_WOD_SEMI) { chunk_t *tmp = pc; if (cpd.consumed) { /* If consumed, then we are on the close sparen. * PAWN: Check the next chunk for a semicolon. If it isn't, then * add a virtual semicolon, which will get handled on the next pass. */ if (cpd.lang_flags & LANG_PAWN) { tmp = chunk_get_next_ncnl(pc); if ((tmp->type != CT_SEMICOLON) && (tmp->type != CT_VSEMICOLON)) { pawn_add_vsemi_after(pc); } } } else { /* Complain if this ISN'T a semicolon, but close out WHILE_OF_DO anyway */ if ((pc->type == CT_SEMICOLON) || (pc->type == CT_VSEMICOLON)) { cpd.consumed = true; set_chunk_parent(pc, CT_WHILE_OF_DO); } else { LOG_FMT(LWARN, "%s:%d: Error: Expected a semicolon for WHILE_OF_DO, but got '%s'\n", cpd.filename, pc->orig_line, get_token_name(pc->type)); cpd.error_count++; } handle_complex_close(frm, pc); } } /* Get the parent type for brace and paren open */ parent = pc->parent_type; if ((pc->type == CT_PAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN) || (pc->type == CT_BRACE_OPEN)) { prev = chunk_get_prev_ncnl(pc); if (prev != NULL) { if ((pc->type == CT_PAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN)) { /* Set the parent for parens and change paren type */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { set_chunk_type(pc, CT_SPAREN_OPEN); parent = frm->pse[frm->pse_tos].type; frm->sparen_count++; } else if (prev->type == CT_FUNCTION) { set_chunk_type(pc, CT_FPAREN_OPEN); parent = CT_FUNCTION; } /* NS_ENUM and NS_OPTIONS are followed by a (type, name) pair */ else if ((prev->type == CT_ENUM) && (cpd.lang_flags & LANG_OC)) { /* Treat both as CT_ENUM since the syntax is identical */ set_chunk_type(pc, CT_FPAREN_OPEN); parent = CT_ENUM; } else { /* no need to set parent */ } } else /* must be CT_BRACE_OPEN */ { /* Set the parent for open braces */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { parent = frm->pse[frm->pse_tos].type; } else if ((prev->type == CT_ASSIGN) && (prev->str[0] == '=')) { parent = CT_ASSIGN; } /* Carry through CT_ENUM parent in NS_ENUM (type, name) { */ else if ((prev->type == CT_FPAREN_CLOSE) && (cpd.lang_flags & LANG_OC) && (prev->parent_type == CT_ENUM)) { parent = CT_ENUM; } else if (prev->type == CT_FPAREN_CLOSE) { parent = CT_FUNCTION; } else { /* no need to set parent */ } } } } /** * Adjust the level for opens & create a stack entry * Note that CT_VBRACE_OPEN has already been handled. */ if ((pc->type == CT_BRACE_OPEN) || (pc->type == CT_PAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN) || (pc->type == CT_ANGLE_OPEN) || (pc->type == CT_MACRO_OPEN) || (pc->type == CT_SQUARE_OPEN)) { frm->level++; if ((pc->type == CT_BRACE_OPEN) || (pc->type == CT_MACRO_OPEN)) { frm->brace_level++; } push_fmr_pse(frm, pc, BS_NONE, "+Open "); frm->pse[frm->pse_tos].parent = parent; set_chunk_parent(pc, parent); } pattern_class patcls = get_token_pattern_class(pc->type); /** Create a stack entry for complex statements IF/DO/FOR/WHILE/SWITCH */ if (patcls == PATCLS_BRACED) { push_fmr_pse(frm, pc, (pc->type == CT_DO) ? BS_BRACE_DO : BS_BRACE2, "+ComplexBraced"); } else if (patcls == PATCLS_PBRACED) { brstage_e bs = BS_PAREN1; if ((pc->type == CT_WHILE) && maybe_while_of_do(pc)) { set_chunk_type(pc, CT_WHILE_OF_DO); bs = BS_WOD_PAREN; } push_fmr_pse(frm, pc, bs, "+ComplexParenBraced"); } else if (patcls == PATCLS_OPBRACED) { push_fmr_pse(frm, pc, BS_OP_PAREN1, "+ComplexOpParenBraced"); } else if (patcls == PATCLS_ELSE) { push_fmr_pse(frm, pc, BS_ELSEIF, "+ComplexElse"); } /* Mark simple statement/expression starts * - after { or } * - after ';', but not if the paren stack top is a paren * - after '(' that has a parent type of CT_FOR */ if ((pc->type == CT_SQUARE_OPEN) || ((pc->type == CT_BRACE_OPEN) && (pc->parent_type != CT_ASSIGN)) || (pc->type == CT_BRACE_CLOSE) || (pc->type == CT_VBRACE_CLOSE) || ((pc->type == CT_SPAREN_OPEN) && (pc->parent_type == CT_FOR)) || (pc->type == CT_COLON) || (pc->type == CT_OC_END) || (chunk_is_semicolon(pc) && (frm->pse[frm->pse_tos].type != CT_PAREN_OPEN) && (frm->pse[frm->pse_tos].type != CT_FPAREN_OPEN) && (frm->pse[frm->pse_tos].type != CT_SPAREN_OPEN))) { LOG_FMT(LSTMT, "%s: %d> reset1 stmt on %s\n", __func__, pc->orig_line, pc->text()); frm->stmt_count = 0; frm->expr_count = 0; } /* Mark expression starts */ chunk_t *tmp = chunk_get_next_ncnl(pc); if ((pc->type == CT_ARITH) || (pc->type == CT_ASSIGN) || (pc->type == CT_CASE) || (pc->type == CT_COMPARE) || ((pc->type == CT_STAR) && tmp && (tmp->type != CT_STAR)) || (pc->type == CT_BOOL) || (pc->type == CT_MINUS) || (pc->type == CT_PLUS) || (pc->type == CT_CARET) || (pc->type == CT_ANGLE_OPEN) || (pc->type == CT_ANGLE_CLOSE) || (pc->type == CT_RETURN) || (pc->type == CT_THROW) || (pc->type == CT_GOTO) || (pc->type == CT_CONTINUE) || (pc->type == CT_PAREN_OPEN) || (pc->type == CT_FPAREN_OPEN) || (pc->type == CT_SPAREN_OPEN) || (pc->type == CT_BRACE_OPEN) || chunk_is_semicolon(pc) || (pc->type == CT_COMMA) || (pc->type == CT_NOT) || (pc->type == CT_INV) || (pc->type == CT_COLON) || (pc->type == CT_QUESTION)) { frm->expr_count = 0; LOG_FMT(LSTMT, "%s: %d> reset expr on %s\n", __func__, pc->orig_line, pc->text()); } } // parse_cleanup
/** * Scan backwards to find the most appropriate spot to split the line * and insert a newline. * * See if this needs special function handling. * Scan backwards and find the best token for the split. * * @param start The first chunk that exceeded the limit */ static void split_line(chunk_t *start) { LOG_FMT(LSPLIT, "%s: line %d, col %d token:%s[%s] (IN_FUNC=%d) ", __func__, start->orig_line, start->column, start->str.c_str(), get_token_name(start->type), (start->flags & (PCF_IN_FCN_DEF | PCF_IN_FCN_CALL)) != 0); /** * break at maximum line length if ls_code_width is true */ if (cpd.settings[UO_ls_code_width].b) { } /* Check to see if we are in a for statement */ else if ((start->flags & PCF_IN_FOR) != 0) { LOG_FMT(LSPLIT, " ** FOR SPLIT **\n"); split_for_stmt(start); if (!is_past_width(start)) { return; } LOG_FMT(LSPLIT, "%s: for split didn't work\n", __func__); } /* If this is in a function call or prototype, split on commas or right * after the open paren */ else if (((start->flags & PCF_IN_FCN_DEF) != 0) || ((start->level == (start->brace_level + 1)) && ((start->flags & PCF_IN_FCN_CALL) != 0))) { LOG_FMT(LSPLIT, " ** FUNC SPLIT **\n"); if (cpd.settings[UO_ls_func_split_full].b) { split_fcn_params_full(start); if (!is_past_width(start)) { return; } } split_fcn_params(start); if (!is_past_width(start)) { return; } LOG_FMT(LSPLIT, "%s: func split didn't work\n", __func__); } /** * Try to find the best spot to split the line */ cw_entry ent; memset(&ent, 0, sizeof(ent)); chunk_t *pc = start; chunk_t *prev; while (((pc = chunk_get_prev(pc)) != NULL) && !chunk_is_newline(pc)) { if (pc->type != CT_SPACE) { try_split_here(ent, pc); /* break at maximum line length */ if ((ent.pc != NULL) && (cpd.settings[UO_ls_code_width].b)) break; } } if (ent.pc == NULL) { LOG_FMT(LSPLIT, "%s: TRY_SPLIT yielded NO SOLUTION for line %d at %s [%s]\n", __func__, start->orig_line, start->str.c_str(), get_token_name(start->type)); } else { LOG_FMT(LSPLIT, "%s: TRY_SPLIT yielded '%s' [%s] on line %d\n", __func__, ent.pc->str.c_str(), get_token_name(ent.pc->type), ent.pc->orig_line); } /* Break before the token instead of after it according to the pos_xxx rules */ if ((chunk_is_token(ent.pc, CT_ARITH) && (cpd.settings[UO_pos_arith].tp & TP_LEAD)) || (chunk_is_token(ent.pc, CT_ASSIGN) && (cpd.settings[UO_pos_assign].tp & TP_LEAD)) || (chunk_is_token(ent.pc, CT_COMPARE) && (cpd.settings[UO_pos_compare].tp & TP_LEAD)) || ((chunk_is_token(ent.pc, CT_COND_COLON) || chunk_is_token(ent.pc, CT_QUESTION)) && (cpd.settings[UO_pos_conditional].tp & TP_LEAD)) || (chunk_is_token(ent.pc, CT_BOOL) && (cpd.settings[UO_pos_bool].tp & TP_LEAD))) { pc = ent.pc; } else { pc = chunk_get_next(ent.pc); } if (pc == NULL) { pc = start; /* Don't break before a close, comma, or colon */ if ((start->type == CT_PAREN_CLOSE) || (start->type == CT_PAREN_OPEN) || (start->type == CT_FPAREN_CLOSE) || (start->type == CT_FPAREN_OPEN) || (start->type == CT_SPAREN_CLOSE) || (start->type == CT_SPAREN_OPEN) || (start->type == CT_ANGLE_CLOSE) || (start->type == CT_BRACE_CLOSE) || (start->type == CT_COMMA) || (start->type == CT_SEMICOLON) || (start->type == CT_VSEMICOLON) || (start->len() == 0)) { LOG_FMT(LSPLIT, " ** NO GO **\n"); /*TODO: Add in logic to handle 'hard' limits by backing up a token */ return; } } /* add a newline before pc */ prev = chunk_get_prev(pc); if ((prev != NULL) && !chunk_is_newline(pc) && !chunk_is_newline(prev)) { int plen = (pc->len() < 5) ? pc->len() : 5; int slen = (start->len() < 5) ? start->len() : 5; LOG_FMT(LSPLIT, " '%.*s' [%s], started on token '%.*s' [%s]\n", plen, pc->str.c_str(), get_token_name(pc->type), slen, start->str.c_str(), get_token_name(start->type)); split_before_chunk(pc); } }
/** * Handles a close paren or brace - just progress the stage, if the end * of the statement is hit, call close_statement() * * @param frm The parse frame * @param pc The current chunk * @return true - done with this chunk, false - keep processing */ static bool handle_complex_close(struct parse_frame *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); chunk_t *next; if (frm->pse[frm->pse_tos].stage == BS_PAREN1) { if (pc->next->type == CT_WHEN) { frm->pse[frm->pse_tos].type = pc->type; frm->pse[frm->pse_tos].stage = BS_CATCH_WHEN; return true; } else { /* PAREN1 always => BRACE2 */ frm->pse[frm->pse_tos].stage = BS_BRACE2; } } else if (frm->pse[frm->pse_tos].stage == BS_BRACE2) { /* BRACE2: IF => ELSE, anyting else => close */ if ((frm->pse[frm->pse_tos].type == CT_IF) || (frm->pse[frm->pse_tos].type == CT_ELSEIF)) { frm->pse[frm->pse_tos].stage = BS_ELSE; /* If the next chunk isn't CT_ELSE, close the statement */ next = chunk_get_next_ncnl(pc); if ((next != NULL) && (next->type != CT_ELSE)) { frm->pse_tos--; print_stack(LBCSPOP, "-IF-HCS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } } else if ((frm->pse[frm->pse_tos].type == CT_TRY) || (frm->pse[frm->pse_tos].type == CT_CATCH)) { frm->pse[frm->pse_tos].stage = BS_CATCH; /* If the next chunk isn't CT_CATCH or CT_FINALLY, close the statement */ next = chunk_get_next_ncnl(pc); if ((next != NULL) && (next->type != CT_CATCH) && (next->type != CT_FINALLY)) { frm->pse_tos--; print_stack(LBCSPOP, "-TRY-HCS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } } else { LOG_FMT(LNOTE, "%s: close_statement on %s BS_BRACE2\n", __func__, get_token_name(frm->pse[frm->pse_tos].type)); frm->pse_tos--; print_stack(LBCSPOP, "-HCC B2 ", frm, pc); if (close_statement(frm, pc)) { return(true); } } } else if (frm->pse[frm->pse_tos].stage == BS_BRACE_DO) { frm->pse[frm->pse_tos].stage = BS_WHILE; } else if (frm->pse[frm->pse_tos].stage == BS_WOD_PAREN) { LOG_FMT(LNOTE, "%s: close_statement on %s BS_WOD_PAREN\n", __func__, get_token_name(frm->pse[frm->pse_tos].type)); frm->pse[frm->pse_tos].stage = BS_WOD_SEMI; print_stack(LBCSPOP, "-HCC WoDP ", frm, pc); } else if (frm->pse[frm->pse_tos].stage == BS_WOD_SEMI) { LOG_FMT(LNOTE, "%s: close_statement on %s BS_WOD_SEMI\n", __func__, get_token_name(frm->pse[frm->pse_tos].type)); frm->pse_tos--; print_stack(LBCSPOP, "-HCC WoDS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } else { /* PROBLEM */ LOG_FMT(LWARN, "%s:%d Error: TOS.type='%s' TOS.stage=%d\n", cpd.filename, pc->orig_line, get_token_name(frm->pse[frm->pse_tos].type), frm->pse[frm->pse_tos].stage); cpd.error_count++; } return(false); } // handle_complex_close
/** * A for statement is too long. * Step backwards and forwards to find the semicolons * Try splitting at the semicolons first. * If that doesn't work, then look for a comma at paren level. * If that doesn't work, then look for an assignment at paren level. * If that doesn't work, then give up. */ static void split_for_stmt(chunk_t *start) { int count = 0; int max_cnt = cpd.settings[UO_ls_for_split_full].b ? 2 : 1; chunk_t *st[2]; chunk_t *pc; chunk_t *open_paren = NULL; int nl_cnt = 0; LOG_FMT(LSPLIT, "%s: starting on %s, line %d\n", __func__, start->str.c_str(), start->orig_line); /* Find the open paren so we know the level and count newlines */ pc = start; while ((pc = chunk_get_prev(pc)) != NULL) { if (pc->type == CT_SPAREN_OPEN) { open_paren = pc; break; } if (pc->nl_count > 0) { nl_cnt += pc->nl_count; } } if (open_paren == NULL) { LOG_FMT(LSYS, "No open paren\n"); return; } /* see if we started on the semicolon */ pc = start; if ((pc->type == CT_SEMICOLON) && (pc->parent_type == CT_FOR)) { st[count++] = pc; } /* first scan backwards for the semicolons */ while ((count < max_cnt) && ((pc = chunk_get_prev(pc)) != NULL) && (pc->flags & PCF_IN_SPAREN)) { if ((pc->type == CT_SEMICOLON) && (pc->parent_type == CT_FOR)) { st[count++] = pc; } } /* And now scan forward */ pc = start; while ((count < max_cnt) && ((pc = chunk_get_next(pc)) != NULL) && (pc->flags & PCF_IN_SPAREN)) { if ((pc->type == CT_SEMICOLON) && (pc->parent_type == CT_FOR)) { st[count++] = pc; } } while (--count >= 0) { LOG_FMT(LSPLIT, "%s: split before %s\n", __func__, st[count]->str.c_str()); split_before_chunk(chunk_get_next(st[count])); } if (!is_past_width(start) || (nl_cnt > 0)) { return; } /* Still past width, check for commas at paren level */ pc = open_paren; while ((pc = chunk_get_next(pc)) != start) { if ((pc->type == CT_COMMA) && (pc->level == (open_paren->level + 1))) { split_before_chunk(chunk_get_next(pc)); if (!is_past_width(pc)) { return; } } } /* Still past width, check for a assignments at paren level */ pc = open_paren; while ((pc = chunk_get_next(pc)) != start) { if ((pc->type == CT_ASSIGN) && (pc->level == (open_paren->level + 1))) { split_before_chunk(chunk_get_next(pc)); if (!is_past_width(pc)) { return; } } } /* Oh, well. We tried. */ }
/** * This function parses or tokenizes the whole buffer into a list. * It has to do some tricks to parse preprocessors. * * If output_text() were called immediately after, two things would happen: * - trailing whitespace are removed. * - leading space & tabs are converted to the appropriate format. * * All the tokens are inserted before ref. If ref is NULL, they are inserted * at the end of the list. Line numbers are relative to the start of the data. */ void tokenize(const deque<int>& data, chunk_t *ref) { tok_ctx ctx(data); chunk_t chunk; chunk_t *pc = NULL; chunk_t *rprev = NULL; struct parse_frame frm; bool last_was_tab = false; memset(&frm, 0, sizeof(frm)); while (ctx.more()) { chunk.reset(); if (!parse_next(ctx, chunk)) { LOG_FMT(LERR, "%s:%d Bailed before the end?\n", cpd.filename, ctx.c.row); cpd.error_count++; break; } /* Don't create an entry for whitespace */ if (chunk.type == CT_WHITESPACE) { last_was_tab = chunk.after_tab; continue; } if (chunk.type == CT_NEWLINE) { last_was_tab = chunk.after_tab; chunk.after_tab = false; chunk.str.clear(); } else if (chunk.type == CT_NL_CONT) { last_was_tab = chunk.after_tab; chunk.after_tab = false; chunk.str = "\\\n"; } else { chunk.after_tab = last_was_tab; last_was_tab = false; } /* Strip trailing whitespace (for CPP comments and PP blocks) */ while ((chunk.str.size() > 0) && ((chunk.str[chunk.str.size() - 1] == ' ') || (chunk.str[chunk.str.size() - 1] == '\t'))) { chunk.str.pop_back(); } /* Store off the end column */ chunk.orig_col_end = ctx.c.col; /* Add the chunk to the list */ rprev = pc; if (rprev != NULL) { pc->flags |= rprev->flags & PCF_COPY_FLAGS; /* a newline can't be in a preprocessor */ if (pc->type == CT_NEWLINE) { pc->flags &= ~PCF_IN_PREPROC; } } if (ref != NULL) { chunk.flags |= PCF_INSERTED; } else { chunk.flags &= ~PCF_INSERTED; } pc = chunk_add_before(&chunk, ref); /* A newline marks the end of a preprocessor */ if (pc->type == CT_NEWLINE) // || (pc->type == CT_COMMENT_MULTI)) { cpd.in_preproc = CT_NONE; cpd.preproc_ncnl_count = 0; } /* Special handling for preprocessor stuff */ if (cpd.in_preproc != CT_NONE) { pc->flags |= PCF_IN_PREPROC; /* Count words after the preprocessor */ if (!chunk_is_comment(pc) && !chunk_is_newline(pc)) { cpd.preproc_ncnl_count++; } /* Figure out the type of preprocessor for #include parsing */ if (cpd.in_preproc == CT_PREPROC) { if ((pc->type < CT_PP_DEFINE) || (pc->type > CT_PP_OTHER)) { pc->type = CT_PP_OTHER; } cpd.in_preproc = pc->type; } } else { /* Check for a preprocessor start */ if ((pc->type == CT_POUND) && ((rprev == NULL) || (rprev->type == CT_NEWLINE))) { pc->type = CT_PREPROC; pc->flags |= PCF_IN_PREPROC; cpd.in_preproc = CT_PREPROC; } } } /* Set the cpd.newline string for this file */ if ((cpd.settings[UO_newlines].le == LE_LF) || ((cpd.settings[UO_newlines].le == LE_AUTO) && (cpd.le_counts[LE_LF] >= cpd.le_counts[LE_CRLF]) && (cpd.le_counts[LE_LF] >= cpd.le_counts[LE_CR]))) { /* LF line ends */ cpd.newline = "\n"; LOG_FMT(LLINEENDS, "Using LF line endings\n"); } else if ((cpd.settings[UO_newlines].le == LE_CRLF) || ((cpd.settings[UO_newlines].le == LE_AUTO) && (cpd.le_counts[LE_CRLF] >= cpd.le_counts[LE_LF]) && (cpd.le_counts[LE_CRLF] >= cpd.le_counts[LE_CR]))) { /* CRLF line ends */ cpd.newline = "\r\n"; LOG_FMT(LLINEENDS, "Using CRLF line endings\n"); } else { /* CR line ends */ cpd.newline = "\r"; LOG_FMT(LLINEENDS, "Using CR line endings\n"); } }
/** * Check the backup-md5 file and copy the input file to a backup if needed. */ int backup_copy_file(const char *filename, const vector<UINT8> &data) { char newpath[1024]; char buffer[128]; char md5_str_in[33]; char md5_str[33]; UINT8 dig[16]; md5_str_in[0] = 0; MD5::Calc(&data[0], data.size(), dig); snprintf(md5_str, sizeof(md5_str), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", dig[0], dig[1], dig[2], dig[3], dig[4], dig[5], dig[6], dig[7], dig[8], dig[9], dig[10], dig[11], dig[12], dig[13], dig[14], dig[15]); /* Create the backup-md5 filename, open it and read the md5 */ snprintf(newpath, sizeof(newpath), "%s%s", filename, UNC_BACKUP_MD5_SUFFIX); FILE *thefile = fopen(newpath, "rb"); if (thefile != NULL) { if (fgets(buffer, sizeof(buffer), thefile) != NULL) { for (int i = 0; buffer[i] != 0; i++) { if (unc_isxdigit(buffer[i])) { md5_str_in[i] = unc_tolower(buffer[i]); } else { md5_str_in[i] = 0; break; } } } fclose(thefile); } /* if the MD5s match, then there is no need to back up the file */ if (memcmp(md5_str, md5_str_in, 32) == 0) { LOG_FMT(LNOTE, "%s: MD5 match for %s\n", __func__, filename); return(SUCCESS); } LOG_FMT(LNOTE, "%s: MD5 mismatch - backing up %s\n", __func__, filename); /* Create the backup file */ snprintf(newpath, sizeof(newpath), "%s%s", filename, UNC_BACKUP_SUFFIX); thefile = fopen(newpath, "wb"); if (thefile != NULL) { int retval = fwrite(&data[0], data.size(), 1, thefile); int my_errno = errno; fclose(thefile); if (retval == 1) { return(SUCCESS); } LOG_FMT(LERR, "fwrite(%s) failed: %s (%d)\n", newpath, strerror(my_errno), my_errno); cpd.error_count++; } else { LOG_FMT(LERR, "fopen(%s) failed: %s (%d)\n", newpath, strerror(errno), errno); cpd.error_count++; } return(FAILURE); } // backup_copy_file