int get() { if (more()) { int ch = data[c.idx++]; switch (ch) { case '\t': c.col = calc_next_tab_column(c.col, cpd.settings[UO_input_tab_size].n); break; case '\n': if (c.last_ch != '\r') { c.row++; c.col = 1; } break; case '\r': c.row++; c.col = 1; break; default: c.col++; break; } c.last_ch = ch; return(ch); } return(-1); }
/** * Count the number of whitespace characters. * * @param pc The structure to update, str is an input. * @return Whether whitespace was parsed */ static bool parse_whitespace(tok_ctx& ctx, chunk_t& pc) { int nl_count = 0; int ch = -2; /* REVISIT: use a better whitespace detector? */ while (ctx.more() && unc_isspace(ctx.peek())) { ch = ctx.get(); /* throw away the whitespace char */ switch (ch) { case '\r': if (ctx.expect('\n')) { /* CRLF ending */ cpd.le_counts[LE_CRLF]++; } else { /* CR ending */ cpd.le_counts[LE_CR]++; } nl_count++; pc.orig_prev_sp = 0; break; case '\n': /* LF ending */ cpd.le_counts[LE_LF]++; nl_count++; pc.orig_prev_sp = 0; break; case '\t': pc.orig_prev_sp += calc_next_tab_column(cpd.column, cpd.settings[UO_input_tab_size].n) - cpd.column; break; case ' ': pc.orig_prev_sp++; break; default: break; } } if (ch != -2) { pc.str.clear(); pc.nl_count = nl_count; pc.type = nl_count ? CT_NEWLINE : CT_WHITESPACE; pc.after_tab = (ctx.c.last_ch == '\t'); return(true); } return(false); } // parse_whitespace
/** * Output a multiline comment without any reformatting other than shifting * it left or right to get the column right. * Oh, and trim trailing whitespace. */ static void output_comment_multi_simple(chunk_t *pc) { int cmt_idx; char ch; int line_count = 0; int ccol; int col_diff = 0; bool nl_end = false; cmt_reflow cmt; unc_text line; output_cmt_start(cmt, pc); if (chunk_is_newline(chunk_get_prev(pc))) { /* The comment should be indented correctly */ col_diff = pc->orig_col - pc->column; } else { /* The comment starts after something else */ col_diff = 0; } ccol = pc->column; cmt_idx = 0; line.clear(); while (cmt_idx < pc->len()) { ch = pc->str[cmt_idx++]; /* handle the CRLF and CR endings. convert both to LF */ if (ch == '\r') { ch = '\n'; if ((cmt_idx < pc->len()) && (pc->str[cmt_idx] == '\n')) { cmt_idx++; } } /* Find the start column */ if (line.size() == 0) { nl_end = false; if (ch == ' ') { ccol++; continue; } else if (ch == '\t') { ccol = calc_next_tab_column(ccol, cpd.settings[UO_input_tab_size].n); continue; } else { //LOG_FMT(LSYS, "%d] Text starts in col %d, col_diff=%d, real=%d\n", // line_count, ccol, col_diff, ccol - col_diff); } } line.append(ch); /* If we just hit an end of line OR we just hit end-of-comment... */ if ((ch == '\n') || (cmt_idx == pc->len())) { line_count++; /* strip trailing tabs and spaces before the newline */ if (ch == '\n') { line.pop_back(); nl_end = true; /* Say we aren't in a preproc to prevent changing any bs-nl */ cmt_trim_whitespace(line, false); } if (line_count > 1) { ccol -= col_diff; } if (line.size() > 0) { cmt.column = ccol; cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); add_text(line); } if (nl_end) { add_char('\n'); } line.clear(); ccol = 1; } } }
void output_comment_multi(chunk_t *pc) { int cmt_col = pc->column; const char *cmt_str; int remaining; char ch; chunk_t *prev; char line[1024]; int line_len; int line_count = 0; int ccol; int col_diff = 0; int xtra = 1; prev = chunk_get_prev(pc); if ((prev != NULL) && (prev->type != CT_NEWLINE)) { cmt_col = pc->orig_col; } else { col_diff = pc->orig_col - pc->column; } // fprintf(stderr, "Indenting1 line %d to col %d (orig=%d) col_diff=%d\n", // pc->orig_line, cmt_col, pc->orig_col, col_diff); xtra = calculate_comment_body_indent(pc->str, pc->len, pc->column); ccol = 1; remaining = pc->len; cmt_str = pc->str; line_len = 0; while (remaining > 0) { ch = *cmt_str; cmt_str++; remaining--; /* handle the CRLF and CR endings. convert both to LF */ if (ch == '\r') { ch = '\n'; if (*cmt_str == '\n') { cmt_str++; remaining--; } } /* Find the start column */ if (line_len == 0) { if (ch == ' ') { ccol++; continue; } else if (ch == '\t') { ccol = calc_next_tab_column(ccol, cpd.settings[UO_input_tab_size].n); continue; } else { //fprintf(stderr, "%d] Text starts in col %d\n", line_count, ccol); } } line[line_len++] = ch; /* If we just hit an end of line OR we just hit end-of-comment... */ if ((ch == '\n') || (remaining == 0)) { line_count++; /* strip trailing tabs and spaces before the newline */ if (ch == '\n') { line_len--; while ((line_len > 0) && ((line[line_len - 1] == ' ') || (line[line_len - 1] == '\t'))) { line_len--; } line[line_len++] = ch; } line[line_len] = 0; if (line_count == 1) { /* this is the first line - add unchanged */ /*TODO: need to support indent_with_tabs mode 1 */ output_to_column(cmt_col, cpd.settings[UO_indent_with_tabs].b); add_text_len(line, line_len); } else { /* This is not the first line, so we need to indent to the * correct column. */ ccol -= col_diff; if (ccol < cmt_col) { ccol = cmt_col; } if (line[0] == '\n') { /* Emtpy line - just a '\n' */ if (cpd.settings[UO_cmt_star_cont].b) { output_to_column(cmt_col, cpd.settings[UO_indent_with_tabs].b); add_text((xtra == 1) ? " *" : "*"); } add_char('\n'); } else { /* If this doesn't start with a '*' or '|' */ if ((line[0] != '*') && (line[0] != '|') && (line[0] != '#') && (line[0] != '\\') && (line[0] != '+')) { output_to_column(cmt_col, cpd.settings[UO_indent_with_tabs].b); if (cpd.settings[UO_cmt_star_cont].b) { add_text((xtra == 1) ? " * " : "* "); } else { add_text(" "); } output_to_column(ccol, cpd.settings[UO_indent_with_tabs].b); } else { output_to_column(cmt_col + xtra, cpd.settings[UO_indent_with_tabs].b); } add_text_len(line, line_len); } } line_len = 0; ccol = 1; } } }
/** * A multiline comment -- woopeee! * The only trick here is that we have to trim out whitespace characters * to get the comment to line up. */ static void output_comment_multi(chunk_t *pc) { int cmt_col; int cmt_idx; int ch; unc_text line; int line_count = 0; int ccol; /* the col of subsequent comment lines */ int col_diff = 0; bool nl_end = false; cmt_reflow cmt; //LOG_FMT(LSYS, "%s: line %d\n", __func__, pc->orig_line); output_cmt_start(cmt, pc); cmt.reflow = (cpd.settings[UO_cmt_reflow_mode].n != 1); cmt_col = cmt.base_col; col_diff = pc->orig_col - cmt.base_col; calculate_comment_body_indent(cmt, pc->str); cmt.cont_text = !cpd.settings[UO_cmt_indent_multi].b ? "" : (cpd.settings[UO_cmt_star_cont].b ? "* " : " "); LOG_CONTTEXT(); //LOG_FMT(LSYS, "Indenting1 line %d to col %d (orig=%d) col_diff=%d xtra=%d cont='%s'\n", // pc->orig_line, cmt_col, pc->orig_col, col_diff, cmt.xtra_indent, cmt.cont_text.c_str()); ccol = pc->column; cmt_idx = 0; line.clear(); while (cmt_idx < pc->len()) { ch = pc->str[cmt_idx++]; /* handle the CRLF and CR endings. convert both to LF */ if (ch == '\r') { ch = '\n'; if ((cmt_idx < pc->len()) && (pc->str[cmt_idx] == '\n')) { cmt_idx++; } } /* Find the start column */ if (line.size() == 0) { nl_end = false; if (ch == ' ') { ccol++; continue; } else if (ch == '\t') { ccol = calc_next_tab_column(ccol, cpd.settings[UO_input_tab_size].n); continue; } else { //LOG_FMT(LSYS, "%d] Text starts in col %d\n", line_count, ccol); } } /* * Now see if we need/must fold the next line with the current to enable * full reflow */ if ((cpd.settings[UO_cmt_reflow_mode].n == 2) && (ch == '\n') && (cmt_idx < pc->len())) { int nxt_len = 0; int next_nonempty_line = -1; int prev_nonempty_line = -1; int nwidx = line.size(); bool star_is_bullet = false; /* strip trailing whitespace from the line collected so far */ while (nwidx > 0) { nwidx--; if ((prev_nonempty_line < 0) && !unc_isspace(line[nwidx]) && (line[nwidx] != '*') && // block comment: skip '*' at end of line ((pc->flags & PCF_IN_PREPROC) ? (line[nwidx] != '\\') || ((line[nwidx + 1] != 'r') && (line[nwidx + 1] != '\n')) : true)) { prev_nonempty_line = nwidx; // last nonwhitespace char in the previous line } } int remaining = pc->len() - cmt_idx; for (nxt_len = 0; (nxt_len <= remaining) && (pc->str[nxt_len] != 'r') && (pc->str[nxt_len] != '\n'); nxt_len++) { if ((next_nonempty_line < 0) && !unc_isspace(pc->str[nxt_len]) && (pc->str[nxt_len] != '*') && ((nxt_len == remaining) || ((pc->flags & PCF_IN_PREPROC) ? (pc->str[nxt_len] != '\\') || ((pc->str[nxt_len + 1] != 'r') && (pc->str[nxt_len + 1] != '\n')) : true))) { next_nonempty_line = nxt_len; // first nonwhitespace char in the next line } } /* * see if we should fold up; usually that'd be a YES, but there are a few * situations where folding/reflowing by merging lines is frowned upon: * * - ASCII art in the comments (most often, these are drawings done in +-\/|.,*) * * - Doxygen/JavaDoc/etc. parameters: these often start with \ or @, at least * something clearly non-alphanumeric (you see where we're going with this?) * * - bullet lists that are closely spaced: bullets are always non-alphanumeric * characters, such as '-' or '+' (or, oh horor, '*' - that's bloody ambiguous * to parse :-( ... with or without '*' comment start prefix, that's the * question, then.) * * - semi-HTML formatted code, e.g. <pre>...</pre> comment sections (NDoc, etc.) * * - New lines which form a new paragraph without there having been added an * extra empty line between the last sentence and the new one. * A bit like this, really; so it is opportune to check if the last line ended * in a terminal (that would be the set '.:;!?') and the new line starts with * a capital. * Though new lines starting with comment delimiters, such as '(', should be * pulled up. * * So it bores down to this: the only folding (& reflowing) that's going to happen * is when the next line starts with an alphanumeric character AND the last * line didn't end with an non-alphanumeric character, except: ',' AND the next * line didn't start with a '*' all of a sudden while the previous one didn't * (the ambiguous '*'-for-bullet case!) */ if ((prev_nonempty_line >= 0) && (next_nonempty_line >= 0) && (((unc_isalnum(line[prev_nonempty_line]) || strchr(",)]", line[prev_nonempty_line])) && (unc_isalnum(pc->str[next_nonempty_line]) || strchr("([", pc->str[next_nonempty_line]))) || (('.' == line[prev_nonempty_line]) && // dot followed by non-capital is NOT a new sentence start unc_isupper(pc->str[next_nonempty_line]))) && !star_is_bullet) { // rewind the line to the last non-alpha: line.resize(prev_nonempty_line + 1); // roll the current line forward to the first non-alpha: cmt_idx += next_nonempty_line; // override the NL and make it a single whitespace: ch = ' '; } } line.append(ch); /* If we just hit an end of line OR we just hit end-of-comment... */ if ((ch == '\n') || (cmt_idx == pc->len())) { line_count++; /* strip trailing tabs and spaces before the newline */ if (ch == '\n') { nl_end = true; line.pop_back(); cmt_trim_whitespace(line, pc->flags & PCF_IN_PREPROC); } //LOG_FMT(LSYS, "[%3d]%s\n", ccol, line); if (line_count == 1) { /* this is the first line - add unchanged */ add_comment_text(line, cmt, false); if (nl_end) { add_char('\n'); } } else { /* This is not the first line, so we need to indent to the * correct column. Each line is indented 0 or more spaces. */ ccol -= col_diff; if (ccol < (cmt_col + 3)) { ccol = cmt_col + 3; } if (line.size() == 0) { /* Empty line - just a '\n' */ if (cpd.settings[UO_cmt_star_cont].b) { cmt.column = cmt_col + cpd.settings[UO_cmt_sp_before_star_cont].n; cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); if (cmt.xtra_indent) { add_char(' '); } add_text(cmt.cont_text); } add_char('\n'); } else { /* If this doesn't start with a '*' or '|'. * '\name' is a common parameter documentation thing. */ if (cpd.settings[UO_cmt_indent_multi].b && (line[0] != '*') && (line[0] != '|') && (line[0] != '#') && ((line[0] != '\\') || unc_isalpha(line[1])) && (line[0] != '+')) { int start_col = cmt_col + cpd.settings[UO_cmt_sp_before_star_cont].n; if (cpd.settings[UO_cmt_star_cont].b) { cmt.column = start_col; cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); if (cmt.xtra_indent) { add_char(' '); } add_text(cmt.cont_text); output_to_column(ccol + cpd.settings[UO_cmt_sp_after_star_cont].n, false); } else { cmt.column = ccol; cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); } } else { cmt.column = cmt_col + cpd.settings[UO_cmt_sp_before_star_cont].n; cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); if (cmt.xtra_indent) { add_char(' '); } int idx; idx = cmt_parse_lead(line, (cmt_idx == pc->len())); if (idx > 0) { cmt.cont_text.set(line, 0, idx); LOG_CONTTEXT(); if ((line.size() >= 2) && (line[0] == '*') && unc_isalnum(line[1])) { line.insert(1, ' '); } } else { add_text(cmt.cont_text); } } add_comment_text(line, cmt, false); if (nl_end) { add_text("\n"); } } } line.clear(); ccol = 1; } } }