int unc_text::compare(const unc_text& ref1, const unc_text& ref2, int len) { int idx, len1, len2; len1 = ref1.size(); len2 = ref2.size(); if (len > 0) { for (idx = 0; (idx < len1) && (idx < len2) && (idx < len); idx++) { if (ref1.m_chars[idx] != ref2.m_chars[idx]) { return(ref1.m_chars[idx] - ref2.m_chars[idx]); } } if (idx == len) { return 0; } return(len1 - len2); } for (idx = 0; (idx < len1) && (idx < len2); idx++) { if (ref1.m_chars[idx] != ref2.m_chars[idx]) { return(ref1.m_chars[idx] - ref2.m_chars[idx]); } } return (len1 - len2); }
bool unc_text::startswith(const unc_text &text, size_t idx) const { size_t si = 0; const auto orig_idx = idx; for ( ; idx < size() && si < text.size(); idx++, si++) { if (text.m_chars[si] != m_chars[idx]) { return(false); } } return(idx != orig_idx && (si == text.size())); }
static int next_up(const unc_text& text, int idx, unc_text& tag) { int offs = 0; while ((idx < text.size()) && unc_isspace(text[idx])) { idx++; offs++; } if (text.startswith(tag, idx)) { return(offs); } return(-1); }
bool unc_text::startswith(const unc_text& text, int idx) const { bool match = false; int si = 0; while ((idx < size()) && (si < text.size())) { if (text.m_chars[si] != m_chars[idx]) { return false; } idx++; si++; match = true; } return(match && (si == text.size())); }
static void add_text(const unc_text& text) { for (int idx = 0; idx < text.size(); idx++) { add_char(text[idx]); } }
int unc_text::compare(const unc_text &ref1, const unc_text &ref2, size_t len, bool tcare) { const size_t len1 = ref1.size(); const size_t len2 = ref2.size(); const auto max_idx = std::min({ len, len1, len2 }); size_t idx = 0; for ( ; idx < max_idx; idx++) { // exactly the same character ? if (ref1.m_chars[idx] == ref2.m_chars[idx]) { continue; } int diff; // Issue #2091 if (tcare) { diff = ref1.m_chars[idx] - ref2.m_chars[idx]; } else { diff = unc_tolower(ref1.m_chars[idx]) - unc_tolower(ref2.m_chars[idx]); } if (diff == 0) { /* * if we're comparing the same character but in different case * we want to favor lower case before upper case (e.g. a before A) * so the order is the reverse of ASCII order (we negate). */ return(-(ref1.m_chars[idx] - ref2.m_chars[idx])); } // return the case-insensitive diff to sort alphabetically return(diff); } if (idx == len) { return(0); } // underflow save: return(len1 - len2); return((len1 > len2) ? (len1 - len2) : -static_cast<int>(len2 - len1)); } // unc_text::compare
/** * Checks for and updates the lead chars. * * @param line the comment line * @return 0=not present, >0=number of chars that are part of the lead */ static int cmt_parse_lead(const unc_text& line, int is_last) { int len = 0; while ((len < 32) && (len < line.size())) { if ((len > 0) && (line[len] == '/')) { /* ignore combined comments */ int tmp = len + 1; while ((tmp < line.size()) && unc_isspace(line[tmp])) { tmp++; } if ((tmp < line.size()) && (line[tmp] == '/')) { return 1; } break; } else if (strchr("*|\\#+", line[len]) == NULL) { break; } len++; } if (len > 30) { return 1; } if ((len > 0) && ((len >= line.size()) || unc_isspace(line[len]))) { return len; } if ((len == 1) && (line[0] == '*')) { return len; } if (is_last && (len > 0)) { return len; } return 0; }
/** * Count the number of characters to the end of the next chunk of text. * If it exceeds the limit, return true. */ static bool next_word_exceeds_limit(const unc_text& text, int idx) { int length = 0; /* Count any whitespace */ while ((idx < text.size()) && unc_isspace(text[idx])) { idx++; length++; } /* Count non-whitespace */ while ((idx < text.size()) && !unc_isspace(text[idx])) { idx++; length++; } return((cpd.column + length - 1) > cpd.settings[UO_cmt_width].n); }
/** * This renders the #if condition to a string buffer. */ static void generate_if_conditional_as_text(unc_text& dst, chunk_t *ifdef) { chunk_t *pc; int column = -1; dst.clear(); for (pc = ifdef; pc != NULL; pc = chunk_get_next(pc)) { if (column == -1) { column = pc->column; } if ((pc->type == CT_NEWLINE) || (pc->type == CT_COMMENT_MULTI) || (pc->type == CT_COMMENT_CPP)) { break; } else if (pc->type == CT_NL_CONT) { dst += ' '; column = -1; } else if ((pc->type == CT_COMMENT) || (pc->type == CT_COMMENT_EMBED)) { } else // if (pc->type == CT_JUNK) || else { int spacing; for (spacing = pc->column - column; spacing > 0; spacing--) { dst += ' '; column++; } dst.append(pc->str); column += pc->len(); } } }
void unc_text::append(const unc_text &ref) { if (ref.size() == 0) { return; } m_logtext.pop_back(); m_logtext.insert(std::end(m_logtext), std::begin(ref.m_logtext), std::end(ref.m_logtext)); m_chars.insert(m_chars.end(), ref.m_chars.begin(), ref.m_chars.end()); }
int unc_text::replace(const char *oldtext, const unc_text& newtext) { int fidx = find(oldtext); int olen = strlen(oldtext); int rcnt = 0; while (fidx >= 0) { rcnt++; erase(fidx, olen); insert(fidx, newtext); fidx = find(oldtext, fidx + newtext.size() - olen + 1); } return(rcnt); }
bool unc_text::equals(const unc_text& ref) const { int len = size(); if (ref.size() != len) { return false; } for (int idx = 0; idx < len; idx++) { if (m_chars[idx] != ref.m_chars[idx]) { return false; } } return true; }
bool unc_text::equals(const unc_text &ref) const { const size_t len = size(); if (ref.size() != len) { return(false); } for (size_t idx = 0; idx < len; idx++) { if (m_chars[idx] != ref.m_chars[idx]) { return(false); } } return(true); }
void unc_text::set(const unc_text& ref, int idx, int len) { int size = ref.size(); fix_len_idx(size, idx, len); m_logok = false; if ((idx == 0) && (len == size)) { m_chars = ref.m_chars; } else { m_chars.resize(len); int di = 0; while (len-- > 0) { m_chars[di++] = ref.m_chars[idx++]; } } }
int unc_text::replace(const char *search_text, const unc_text &replace_text) { const size_t s_len = strlen(search_text); const size_t r_len = replace_text.size(); int rcnt = 0; int fidx = find(search_text); while (fidx >= 0) { rcnt++; erase(static_cast<size_t>(fidx), s_len); (static_cast<size_t>(fidx) >= m_chars.size()) ? append(replace_text) : insert(static_cast<size_t>(fidx), replace_text); fidx = find(search_text, static_cast<size_t>(fidx) + r_len); } return(rcnt); }
void unc_text::set(const unc_text &ref, size_t idx, size_t len) { const auto ref_size = ref.size(); if (len == ref_size) { m_chars = ref.m_chars; update_logtext(); return; } m_chars.resize(len); len = fix_len_idx(ref_size, idx, len); for (size_t di = 0; len > 0; di++, idx++, len--) { m_chars[di] = ref.m_chars[idx]; } update_logtext(); }
void unc_text::insert(size_t idx, const unc_text &ref) { if (ref.size() == 0) { return; } if (idx >= m_chars.size()) { throw out_of_range(string(__func__) + ":" + to_string(__LINE__) + " - idx >= m_chars.size()"); } const auto utf8_idx = getLogTextUtf8Len(m_chars, idx); // (A+B) remove \0 from both containers, add back a single at the end m_logtext.pop_back(); // A m_logtext.insert(std::next(std::begin(m_logtext), utf8_idx), std::begin(ref.m_logtext), std::prev(std::end(ref.m_logtext))); // B m_logtext.push_back('\0'); m_chars.insert(std::next(std::begin(m_chars), idx), std::begin(ref.m_chars), std::end(ref.m_chars)); }
/** * Scans a multiline comment to determine the following: * - the extra indent of the non-first line (0 or 1) * - the continuation text ('' or '* ') * * The decision is based on: * - cmt_indent_multi * - cmt_star_cont * - the first line length * - the second line leader length * - the last line length * * If the first and last line are the same length and don't contain any alnum * chars and (the first line len > 2 or the second leader is the same as the * first line length), then the indent is 0. * * If the leader on the second line is 1 wide or missing, then the indent is 1. * * Otherwise, the indent is 0. * * @param str The comment string * @param len Length of the comment * @param start_col Starting column * @return 0 or 1 */ static void calculate_comment_body_indent(cmt_reflow &cmt, const unc_text& str) { int idx = 0; int first_len = 0; int last_len = 0; int width = 0; int len = str.size(); cmt.xtra_indent = 0; if (!cpd.settings[UO_cmt_indent_multi].b) { return; } if (cpd.settings[UO_cmt_multi_check_last].b) { /* find the last line length */ for (idx = len - 1; idx > 0; idx--) { if ((str[idx] == '\n') || (str[idx] == '\r')) { idx++; while ((idx < len) && ((str[idx] == ' ') || (str[idx] == '\t'))) { idx++; } last_len = len - idx; break; } } } /* find the first line length */ for (idx = 0; idx < len; idx++) { if ((str[idx] == '\n') || (str[idx] == '\r')) { first_len = idx; while ((str[first_len - 1] == ' ') || (str[first_len - 1] == '\t')) { first_len--; } /* handle DOS endings */ if ((str[idx] == '\r') && (str[idx + 1] == '\n')) { idx++; } idx++; break; } } /* Scan the second line */ width = 0; for (/* nada */; idx < len - 1; idx++) { if ((str[idx] == ' ') || (str[idx] == '\t')) { if (width > 0) { break; } continue; } if ((str[idx] == '\n') || (str[idx] == '\r')) { /* Done with second line */ break; } /* Count the leading chars */ if ((str[idx] == '*') || (str[idx] == '|') || (str[idx] == '\\') || (str[idx] == '#') || (str[idx] == '+')) { width++; } else { if ((width != 1) || (str[idx - 1] != '*')) { width = 0; } break; } } //LOG_FMT(LSYS, "%s: first=%d last=%d width=%d\n", __func__, first_len, last_len, width); /*TODO: make the first_len minimum (4) configurable? */ if ((first_len == last_len) && ((first_len > 4) || (first_len == width))) { return; } cmt.xtra_indent = ((width == 2) ? 0 : 1); }
/** * text starts with '$('. see if this matches a keyword and add text based * on that keyword. * @return the number of characters eaten from the text */ static int add_comment_kw(const unc_text& text, int idx, cmt_reflow& cmt) { if (text.startswith("$(filename)", idx)) { add_text(path_basename(cpd.filename)); return(11); } if (text.startswith("$(class)", idx)) { chunk_t *tmp = get_next_class(cmt.pc); if (tmp != NULL) { add_text(tmp->str); return(8); } } /* If we can't find the function, we are done */ chunk_t *fcn = get_next_function(cmt.pc); if (fcn == NULL) { return(0); } if (text.startswith("$(message)", idx)) { add_text(fcn->str); chunk_t *tmp = chunk_get_next_ncnl(fcn); chunk_t *word = NULL; while (tmp) { if ((tmp->type == CT_BRACE_OPEN) || (tmp->type == CT_SEMICOLON)) { break; } if (tmp->type == CT_OC_COLON) { if (word != NULL) { add_text(word->str); word = NULL; } add_text(":"); } if (tmp->type == CT_WORD) { word = tmp; } tmp = chunk_get_next_ncnl(tmp); } return(10); } if (text.startswith("$(function)", idx)) { if (fcn->parent_type == CT_OPERATOR) { add_text("operator "); } add_text(fcn->str); return(11); } if (text.startswith("$(javaparam)", idx)) { add_comment_javaparam(fcn, cmt); return(12); } if (text.startswith("$(fclass)", idx)) { chunk_t *tmp = chunk_get_prev_ncnl(fcn); if ((tmp != NULL) && (tmp->type == CT_OPERATOR)) { tmp = chunk_get_prev_ncnl(tmp); } if ((tmp != NULL) && ((tmp->type == CT_DC_MEMBER) || (tmp->type == CT_MEMBER))) { tmp = chunk_get_prev_ncnl(tmp); add_text(tmp->str); return(9); } } return(0); }
/** * Outputs a comment. The initial opening '//' may be included in the text. * Subsequent openings (if combining comments), should not be included. * The closing (for C/D comments) should not be included. * * TODO: * If reflowing text, the comment should be added one word (or line) at a time. * A newline should only be sent if a blank line is encountered or if the next * line is indented beyond the current line (optional?). * If the last char on a line is a ':' or '.', then the next line won't be * combined. */ static void add_comment_text(const unc_text& text, cmt_reflow& cmt, bool esc_close) { bool was_star = false; bool was_slash = false; bool was_dollar = false; bool in_word = false; int tmp; int len = text.size(); for (int idx = 0; idx < len; idx++) { if (!was_dollar && cmt.kw_subst && (text[idx] == '$') && (len > (idx + 3)) && (text[idx + 1] == '(')) { idx += add_comment_kw(text, idx, cmt); if (idx >= len) { break; } } /* Split the comment */ if (text[idx] == '\n') { in_word = false; add_char('\n'); cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); if (cmt.xtra_indent) { add_char(' '); } /* hack to get escaped newlines to align and not dup the leading '//' */ tmp = next_up(text, idx + 1, cmt.cont_text); if (tmp < 0) { add_text(cmt.cont_text); } else { idx += tmp; } } else if (cmt.reflow && (text[idx] == ' ') && (cpd.settings[UO_cmt_width].n > 0) && ((cpd.column > cpd.settings[UO_cmt_width].n) || next_word_exceeds_limit(text, idx))) { in_word = false; add_char('\n'); cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); if (cmt.xtra_indent) { add_char(' '); } add_text(cmt.cont_text); } else { /* Escape a C closure in a CPP comment */ if (esc_close && ((was_star && (text[idx] == '/')) || (was_slash && (text[idx] == '*')))) { add_char(' '); } if (!in_word && !unc_isspace(text[idx])) { cmt.word_count++; } in_word = !unc_isspace(text[idx]); add_char(text[idx]); was_star = (text[idx] == '*'); was_slash = (text[idx] == '/'); was_dollar = (text[idx] == '$'); } } }
static void cmt_trim_whitespace(unc_text& line, bool in_preproc) { /* Remove trailing whitespace on the line */ while ((line.size() > 0) && ((line.back() == ' ') || (line.back() == '\t'))) { line.pop_back(); } /* If in a preproc, shift any bs-nl back to the comment text */ if (in_preproc && (line.size() > 1) && (line.back() == '\\')) { bool do_space = false; /* If there was any space before the backslash, change it to 1 space */ line.pop_back(); while ((line.size() > 0) && ((line.back() == ' ') || (line.back() == '\t'))) { do_space = true; line.pop_back(); } if (do_space) { line.append(' '); } line.append('\\'); } }