diff options
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp')
-rw-r--r-- | debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp | 798 |
1 files changed, 798 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp new file mode 100644 index 00000000..66b5f4ff --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/width.cpp @@ -0,0 +1,798 @@ +/** + * @file width.cpp + * Limits line width. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "width.h" + +#include "indent.h" +#include "newlines.h" +#include "prototypes.h" + + +constexpr static auto LCURRENT = LSPLIT; + +using namespace uncrustify; + + +/** + * abbreviations used: + * - fparen = function parenthesis + */ + +struct SplitEntry +{ + Chunk *pc; + size_t pri; + + SplitEntry() + : pc(Chunk::NullChunkPtr) + , pri(0) {} +}; + + +struct TokenPriority +{ + E_Token tok; + size_t pri; +}; + + +static inline bool is_past_width(Chunk *pc); + + +//! Split right after the chunk +static void split_before_chunk(Chunk *pc); + + +static size_t get_split_pri(E_Token tok); + + +/** + * Checks to see if pc is a better spot to split. + * This should only be called going BACKWARDS (ie prev) + * A lower level wins + * + * Splitting Preference: + * - semicolon + * - comma + * - boolean op + * - comparison + * - arithmetic op + * - assignment + * - concatenated strings + * - ? : + * - function open paren not followed by close paren + */ +static void try_split_here(SplitEntry &ent, Chunk *pc); + + +/** + * 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 bool split_line(Chunk *pc); + + +/** + * Figures out where to split a template + * + * + * @param start the offending token + */ +static void split_template(Chunk *start); + + +/** + * Splits the parameters at every comma that is at the fparen level. + * + * @param start the offending token + */ +static void split_fcn_params_full(Chunk *start); + + +/** + * 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 *start); + + +static inline bool is_past_width(Chunk *pc) +{ + // allow char to sit at last column by subtracting 1 + size_t currCol = pc->GetColumn() + pc->Len() - 1; + bool past_width = currCol > options::code_width(); + + LOG_FMT(LSPLIT, "%s(%d): orig line %zu, orig col %zu, curr col %zu, text '%s', past width %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), currCol, pc->Text(), + past_width ? "YES" : "NO"); + return(past_width); +} + + +static void split_before_chunk(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d): Text() '%s'\n", __func__, __LINE__, pc->Text()); + + Chunk *prev = pc->GetPrev(); + + if ( !pc->IsNewline() + && !prev->IsNewline()) + { + newline_add_before(pc); + // Mark chunk as continuation line, so indentation can be + // correctly set over multiple passes + pc->SetFlagBits(PCF_CONT_LINE); + + // Mark open and close parens as continuation line chunks. + // This will prevent an additional level and frame to be + // added to the current frame stack (issue 3105). + if ( prev->Is(CT_PAREN_OPEN) + || prev->Is(CT_LPAREN_OPEN) + || prev->Is(CT_SPAREN_OPEN) + || prev->Is(CT_FPAREN_OPEN) + || prev->Is(CT_SQUARE_OPEN) + || prev->Is(CT_ANGLE_OPEN)) + { + LOG_FMT(LSPLIT, "%s(%d): set PCF_LINE_CONT for prev text '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, prev->Text(), prev->GetOrigLine(), prev->GetOrigCol()); + + prev->SetFlagBits(PCF_CONT_LINE); + Chunk *closing_paren = prev->GetClosingParen(); + + if (closing_paren->IsNotNullChunk()) + { + closing_paren->SetFlagBits(PCF_CONT_LINE); + } + } + // reindent needs to include the indent_continue value and was off by one + log_rule_B("indent_columns"); + log_rule_B("indent_continue"); + reindent_line(pc, pc->GetBraceLevel() * options::indent_columns() + + abs(options::indent_continue()) + 1); + cpd.changes++; + } +} // split_before_chunk + + +static TokenPriority pri_table[] = +{ + { CT_SEMICOLON, 1 }, + { CT_COMMA, 2 }, + { CT_BOOL, 3 }, + { CT_COMPARE, 4 }, + { CT_SHIFT, 5 }, + { CT_ARITH, 6 }, + { CT_CARET, 7 }, + { CT_ASSIGN, 9 }, + { CT_STRING, 10 }, + { CT_FOR_COLON, 11 }, + { CT_QUESTION, 20 }, // allow break in ? : for ls_code_width + { CT_COND_COLON, 20 }, + { CT_FPAREN_OPEN, 21 }, // break after function open paren not followed by close paren + { CT_QUALIFIER, 25 }, + { CT_CLASS, 25 }, + { CT_STRUCT, 25 }, + { CT_TYPE, 25 }, + { CT_TYPENAME, 25 }, + { CT_VOLATILE, 25 }, +}; + + +void do_code_width() +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d)\n", __func__, __LINE__); + + // If indent_continue is negative, we want to look for long lines splits, + // so raise CT_FPAREN_OPEN priority to get better results. + if (options::indent_continue() < 0) + { + for (TokenPriority &token : pri_table) + { + if (token.tok == CT_FPAREN_OPEN) + { + token.pri = 8; // Before assignment priority + break; + } + } + } + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if ( !pc->IsCommentOrNewline() + && pc->IsNot(CT_SPACE) + && is_past_width(pc)) + { + if ( pc->Is(CT_VBRACE_CLOSE) // don't break if a vbrace close + && pc->IsLastChunkOnLine()) // is the last chunk on its line + { + continue; + } + bool split_OK = split_line(pc); + + if (split_OK) + { + // After a line split it is necessary to reindent the text before considering + // further splits. This avoid splits out of position which would produce an + // awkward result in some cases when a line needs more that one split. + // After the split, skip over the remainder of the line. + Chunk *nextNl = pc->GetNextNl(); + LOG_FMT(LSPLIT, "%s(%d): orig line %zu, orig col %zu, text '%s' splitted\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc = nextNl; + } + else + { + LOG_FMT(LSPLIT, "%s(%d): orig line %zu, orig col %zu, text '%s' not splitted\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + break; + } + } + } +} // do_code_width + + +static size_t get_split_pri(E_Token tok) +{ + for (TokenPriority token : pri_table) + { + if (token.tok == tok) + { + return(token.pri); + } + } + + return(100); // Bigger than any valid priority +} + + +static void try_split_here(SplitEntry &ent, Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + size_t pc_pri = get_split_pri(pc->GetType()); + LOG_FMT(LSPLIT, "%s(%d): text '%s', orig col %zu pc_pri %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigCol(), pc_pri); + + if (pc_pri == 0) + { + LOG_FMT(LSPLIT, "%s(%d): pc_pri is 0, return\n", __func__, __LINE__); + return; + } + // Can't split after a newline + Chunk *prev = pc->GetPrev(); + + if ( prev->IsNullChunk() + || ( prev->IsNewline() + && pc->IsNot(CT_STRING))) + { + if (prev->IsNotNullChunk()) + { + LOG_FMT(LSPLIT, "%s(%d): can't split after a newline, orig line is %zu, return\n", + __func__, __LINE__, prev->GetOrigLine()); + } + return; + } + + // Can't split a function without arguments + if (pc->Is(CT_FPAREN_OPEN)) + { + Chunk *next = pc->GetNext(); + + if (next->Is(CT_FPAREN_CLOSE)) + { + LOG_FMT(LSPLIT, "%s(%d): can't split a function without arguments, return\n", __func__, __LINE__); + return; + } + } + + // Only split concatenated strings + if (pc->Is(CT_STRING)) + { + Chunk *next = pc->GetNext(); + + if (next->IsNot(CT_STRING)) + { + LOG_FMT(LSPLIT, "%s(%d): only split concatenated strings, return\n", __func__, __LINE__); + return; + } + } + + // keep common groupings unless ls_code_width + if ( !options::ls_code_width() + && pc_pri >= 22) + { + LOG_FMT(LSPLIT, "%s(%d): keep common groupings unless ls_code_width, return\n", __func__, __LINE__); + return; + } + + // don't break after last term of a qualified type + if (pc_pri == 25) + { + Chunk *next = pc->GetNext(); + + if ( next->IsNot(CT_WORD) + && (get_split_pri(next->GetType()) != 25)) + { + LOG_FMT(LSPLIT, "%s(%d): don't break after last term of a qualified type, return\n", __func__, __LINE__); + return; + } + } + + if ( ent.pc->IsNullChunk() + || pc_pri < ent.pri + || ( pc_pri == ent.pri + && pc->IsNot(CT_FPAREN_OPEN) + && pc->GetLevel() < ent.pc->GetLevel())) + { + LOG_FMT(LSPLIT, "%s(%d): found possible split\n", __func__, __LINE__); + ent.pc = pc; + ent.pri = pc_pri; + } +} // try_split_here + + +static bool split_line(Chunk *start) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d): start text '%s', orig line %zu, orig col %zu, type %s\n", + __func__, __LINE__, start->Text(), start->GetOrigLine(), start->GetOrigCol(), get_token_name(start->GetType())); + LOG_FMT(LSPLIT, " flags "); + log_pcf_flags(LSPLIT, start->GetFlags()); + LOG_FMT(LSPLIT, " parent type %s, (PCF_IN_FCN_DEF %s), (PCF_IN_FCN_CALL %s)\n", + get_token_name(start->GetParentType()), + start->TestFlags((PCF_IN_FCN_DEF)) ? "TRUE" : "FALSE", + start->TestFlags((PCF_IN_FCN_CALL)) ? "TRUE" : "FALSE"); + + // break at maximum line length if ls_code_width is true + // Issue #2432 + if (start->TestFlags(PCF_ONE_LINER)) + { + LOG_FMT(LSPLIT, "%s(%d): ** ONE LINER SPLIT **\n", __func__, __LINE__); + undo_one_liner(start); + newlines_cleanup_braces(false); + // Issue #1352 + cpd.changes++; + return(false); + } + + if (options::ls_code_width()) + { + log_rule_B("ls_code_width"); + } + else if (start->TestFlags(PCF_IN_FOR)) + { + // Check to see if we are in a for statement + LOG_FMT(LSPLIT, " ** FOR SPLIT **\n"); + split_for_stmt(start); + + if (!is_past_width(start)) + { + return(true); + } + LOG_FMT(LSPLIT, "%s(%d): for split didn't work\n", __func__, __LINE__); + } + else if ( start->TestFlags(PCF_IN_FCN_DEF) + || start->TestFlags(PCF_IN_FCN_CALL) + || start->GetParentType() == CT_FUNC_PROTO) // Issue #1169 + { + /* + * If this is in a function call or prototype, split on commas or right + * after the open parenthesis + */ + LOG_FMT(LSPLIT, " ** FUNC SPLIT **\n"); + + if (options::ls_func_split_full()) + { + log_rule_B("ls_func_split_full"); + + split_fcn_params_full(start); + + if (!is_past_width(start)) + { + return(true); + } + } + } + else if (start->TestFlags(PCF_IN_TEMPLATE)) + { + /* + * If this is in a template, split on commas, Issue #1170 + */ + LOG_FMT(LSPLIT, " ** TEMPLATE SPLIT **\n"); + split_template(start); + return(true); + } + // Try to find the best spot to split the line + LOG_FMT(LSPLIT, "%s(%d): try to find a split point\n", __func__, __LINE__); + SplitEntry ent; + ent.pc = Chunk::NullChunkPtr; + ent.pri = CT_UNKNOWN; + + Chunk *pc = start->GetPrev(); + Chunk *prev; + + while ( pc->IsNotNullChunk() + && !pc->IsNewline()) + { + LOG_FMT(LSPLIT, "%s(%d): text '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + if (pc->IsNot(CT_SPACE)) + { + try_split_here(ent, pc); + + // break at maximum line length + if ( ent.pc->IsNotNullChunk() + && options::ls_code_width()) + { + log_rule_B("ls_code_width"); + LOG_FMT(LSPLIT, "%s(%d): found split\n", __func__, __LINE__); + break; + } + } + pc = pc->GetPrev(); + } + + if (ent.pc->IsNullChunk()) + { + LOG_FMT(LSPLIT, "%s(%d): TRY_SPLIT yielded NO SOLUTION for orig line %zu at '%s' [%s]\n", + __func__, __LINE__, start->GetOrigLine(), start->Text(), get_token_name(start->GetType())); + } + else + { + LOG_FMT(LSPLIT, "%s(%d): TRY_SPLIT yielded '%s' [%s] on orig line %zu\n", + __func__, __LINE__, ent.pc->Text(), get_token_name(ent.pc->GetType()), ent.pc->GetOrigLine()); + LOG_FMT(LSPLIT, "%s(%d): ent at '%s', orig col is %zu\n", + __func__, __LINE__, ent.pc->Text(), ent.pc->GetOrigCol()); + } + + // Break before the token instead of after it according to the pos_xxx rules + if (ent.pc->IsNullChunk()) + { + pc = Chunk::NullChunkPtr; + } + else + { + log_rule_B("pos_arith"); + log_rule_B("pos_assign"); + log_rule_B("pos_compare"); + log_rule_B("pos_conditional"); + log_rule_B("pos_shift"); + log_rule_B("pos_bool"); + + if ( ( ent.pc->Is(CT_SHIFT) + && (options::pos_shift() & TP_LEAD)) + || ( ( ent.pc->Is(CT_ARITH) + || ent.pc->Is(CT_CARET)) + && (options::pos_arith() & TP_LEAD)) + || ( ent.pc->Is(CT_ASSIGN) + && (options::pos_assign() & TP_LEAD)) + || ( ent.pc->Is(CT_COMPARE) + && (options::pos_compare() & TP_LEAD)) + || ( ( ent.pc->Is(CT_COND_COLON) + || ent.pc->Is(CT_QUESTION)) + && (options::pos_conditional() & TP_LEAD)) + || ( ent.pc->Is(CT_BOOL) + && (options::pos_bool() & TP_LEAD))) + { + pc = ent.pc; + } + else + { + pc = ent.pc->GetNext(); + } + LOG_FMT(LSPLIT, "%s(%d): at '%s', orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigCol()); + } + bool move_forward = false; + + if (pc->IsNullChunk()) + { + pc = start; + Chunk *next = pc->GetNext(); + + // On comma, close parenthesis/bracket/braces or semicolon, empty + // parenthesis/brackets/braces pairs, skip after them since they + // are small chunks and the split looks much better. + if ( pc->Is(CT_COMMA) + || pc->IsSemicolon() + || pc->IsParenClose() + || pc->IsBraceClose() + || pc->Is(CT_ANGLE_CLOSE) + || pc->Is(CT_SQUARE_CLOSE) + || ( pc->IsParenOpen() + && next->IsParenClose()) + || ( pc->IsBraceOpen() + && next->IsBraceClose()) + || ( pc->Is(CT_SQUARE_OPEN) + && next->Is(CT_SQUARE_CLOSE)) + || pc->Len() == 0) + { + LOG_FMT(LSPLIT, "Move forward past the chuck"); + move_forward = true; + } + } + // Add a newline before 'pc', if possible. + // If 'pc' is the first chunk in the line, split after it since it is + // already past the allowed code width. If the next chunk is a comma, close + // parenthesis/bracket/braces or semicolon, skip after them since they + // are small chunks and the split looks much better. Also skip over + // empty parenthesis/brackets/braces pairs. + prev = pc->GetPrev(); + + if ( prev->IsNullChunk() + || pc->IsNewline() + || prev->IsNewline() + || move_forward) + { + pc = pc->GetNext(); + Chunk *next = pc->GetNext(); + + while ( pc->Is(CT_COMMA) + || pc->IsSemicolon() + || pc->IsParenClose() + || pc->IsBraceClose() + || pc->Is(CT_ANGLE_CLOSE) + || pc->Is(CT_SQUARE_CLOSE) + || ( pc->IsParenOpen() + && next->IsParenClose()) + || ( pc->IsBraceOpen() + && next->IsBraceClose()) + || ( pc->Is(CT_SQUARE_OPEN) + && next->Is(CT_SQUARE_CLOSE))) + { + pc = next; + next = pc->GetNext(); + } + } + prev = pc->GetPrev(); + + if ( prev->IsNotNullChunk() + && !pc->IsNewline() + && !prev->IsNewline()) + { + //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->Text(), get_token_name(pc->GetType()), + // slen, start->Text(), get_token_name(start->GetType())); + LOG_FMT(LSPLIT, "%s(%d): Text() '%s', type %s, started on token '%s', type %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), + start->Text(), get_token_name(start->GetType())); + + split_before_chunk(pc); + } + return(true); +} // split_line + + +/* + * The for statement split algorithm works as follows: + * 1. Step backwards and forwards to find the semicolons + * 2. Try splitting at the semicolons first. + * 3. If that doesn't work, then look for a comma at paren level. + * 4. If that doesn't work, then look for an assignment at paren level. + * 5. If that doesn't work, then give up. + */ +static void split_for_stmt(Chunk *start) +{ + LOG_FUNC_ENTRY(); + // how many semicolons (1 or 2) do we need to find + log_rule_B("ls_for_split_full"); + size_t max_cnt = options::ls_for_split_full() ? 2 : 1; + Chunk *open_paren = Chunk::NullChunkPtr; + size_t nl_cnt = 0; + + LOG_FMT(LSPLIT, "%s: starting on %s, line %zu\n", + __func__, start->Text(), start->GetOrigLine()); + + // Find the open paren so we know the level and count newlines + Chunk *pc = start; + + while ((pc = pc->GetPrev())->IsNotNullChunk()) + { + if (pc->Is(CT_SPAREN_OPEN)) + { + open_paren = pc; + break; + } + + if (pc->GetNlCount() > 0) + { + nl_cnt += pc->GetNlCount(); + } + } + + if (open_paren->IsNullChunk()) + { + LOG_FMT(LSPLIT, "No open paren\n"); + return; + } + // see if we started on the semicolon + int count = 0; + Chunk *st[2]; + + pc = start; + + if ( pc->Is(CT_SEMICOLON) + && pc->GetParentType() == CT_FOR) + { + st[count++] = pc; + } + + // first scan backwards for the semicolons + while ( (count < static_cast<int>(max_cnt)) + && ((pc = pc->GetPrev())->IsNotNullChunk()) + && pc->IsNotNullChunk() + && pc->TestFlags(PCF_IN_SPAREN)) + { + if ( pc->Is(CT_SEMICOLON) + && pc->GetParentType() == CT_FOR) + { + st[count++] = pc; + } + } + // And now scan forward + pc = start; + + while ( (count < static_cast<int>(max_cnt)) + && ((pc = pc->GetNext())->IsNotNullChunk()) + && pc->TestFlags(PCF_IN_SPAREN)) + { + if ( pc->Is(CT_SEMICOLON) + && pc->GetParentType() == CT_FOR) + { + st[count++] = pc; + } + } + + while (--count >= 0) + { + // TODO: st[0] may be uninitialized here + LOG_FMT(LSPLIT, "%s(%d): split before %s\n", __func__, __LINE__, st[count]->Text()); + split_before_chunk(st[count]->GetNext()); + } + + if ( !is_past_width(start) + || nl_cnt > 0) + { + return; + } + // Still past width, check for commas at parentheses level + pc = open_paren; + + while ((pc = pc->GetNext()) != start) + { + if ( pc->Is(CT_COMMA) + && (pc->GetLevel() == (open_paren->GetLevel() + 1))) + { + split_before_chunk(pc->GetNext()); + + if (!is_past_width(pc)) + { + return; + } + } + } + // Still past width, check for a assignments at parentheses level + pc = open_paren; + + while ((pc = pc->GetNext()) != start) + { + if ( pc->Is(CT_ASSIGN) + && (pc->GetLevel() == (open_paren->GetLevel() + 1))) + { + split_before_chunk(pc->GetNext()); + + if (!is_past_width(pc)) + { + return; + } + } + } + // Oh, well. We tried. +} // split_for_stmt + + +static void split_fcn_params_full(Chunk *start) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d): start at '%s'\n", __func__, __LINE__, start->Text()); + + // Find the opening function parenthesis + Chunk *fpo = start; + + LOG_FMT(LSPLIT, " %s(%d): search for opening function parenthesis\n", __func__, __LINE__); + + while ((fpo = fpo->GetPrev())->IsNotNullChunk()) + { + LOG_FMT(LSPLIT, " %s(%d): %s, orig col is %zu, level is %zu\n", + __func__, __LINE__, fpo->Text(), fpo->GetOrigCol(), fpo->GetLevel()); + + if ( fpo->Is(CT_FPAREN_OPEN) + && (fpo->GetLevel() == start->GetLevel() - 1)) + { + LOG_FMT(LSPLIT, " %s(%d): found open paren\n", __func__, __LINE__); + break; // opening parenthesis found. Issue #1020 + } + } + // Now break after every comma + Chunk *pc = fpo->GetNextNcNnl(); + + while (pc->IsNotNullChunk()) + { + if (pc->GetLevel() <= fpo->GetLevel()) + { + break; + } + + if ( (pc->GetLevel() == (fpo->GetLevel() + 1)) + && pc->Is(CT_COMMA)) + { + split_before_chunk(pc->GetNext()); + } + pc = pc->GetNextNcNnl(); + } +} + + +static void split_template(Chunk *start) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, " %s(%d): start %s\n", __func__, __LINE__, start->Text()); + LOG_FMT(LSPLIT, " %s(%d): back up until the prev is a comma\n", __func__, __LINE__); + + // back up until the prev is a comma + Chunk *prev = start; + + while ((prev = prev->GetPrev())->IsNotNullChunk()) + { + LOG_FMT(LSPLIT, " %s(%d): prev '%s'\n", __func__, __LINE__, prev->Text()); + + if ( prev->IsNewline() + || prev->Is(CT_COMMA)) + { + break; + } + } + + if ( prev->IsNotNullChunk() + && !prev->IsNewline()) + { + LOG_FMT(LSPLIT, " %s(%d):", __func__, __LINE__); + LOG_FMT(LSPLIT, " -- ended on %s --\n", get_token_name(prev->GetType())); + Chunk *pc = prev->GetNext(); + newline_add_before(pc); + size_t min_col = 1; + + log_rule_B("indent_continue"); + + if (options::indent_continue() == 0) + { + log_rule_B("indent_columns"); + min_col += options::indent_columns(); + } + else + { + min_col += abs(options::indent_continue()); + } + reindent_line(pc, min_col); + cpd.changes++; + } +} // split_templatefcn_params |