1 1.174 rillig /* $NetBSD: pr_comment.c,v 1.174 2025/01/04 10:28:08 rillig Exp $ */ 2 1.4 tls 3 1.11 kamil /*- 4 1.11 kamil * SPDX-License-Identifier: BSD-4-Clause 5 1.11 kamil * 6 1.11 kamil * Copyright (c) 1985 Sun Microsystems, Inc. 7 1.5 mrg * Copyright (c) 1980, 1993 8 1.5 mrg * The Regents of the University of California. All rights reserved. 9 1.1 cgd * All rights reserved. 10 1.1 cgd * 11 1.1 cgd * Redistribution and use in source and binary forms, with or without 12 1.1 cgd * modification, are permitted provided that the following conditions 13 1.1 cgd * are met: 14 1.1 cgd * 1. Redistributions of source code must retain the above copyright 15 1.1 cgd * notice, this list of conditions and the following disclaimer. 16 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 cgd * notice, this list of conditions and the following disclaimer in the 18 1.1 cgd * documentation and/or other materials provided with the distribution. 19 1.1 cgd * 3. All advertising materials mentioning features or use of this software 20 1.1 cgd * must display the following acknowledgement: 21 1.1 cgd * This product includes software developed by the University of 22 1.1 cgd * California, Berkeley and its contributors. 23 1.1 cgd * 4. Neither the name of the University nor the names of its contributors 24 1.1 cgd * may be used to endorse or promote products derived from this software 25 1.1 cgd * without specific prior written permission. 26 1.1 cgd * 27 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 1.1 cgd * SUCH DAMAGE. 38 1.1 cgd */ 39 1.1 cgd 40 1.6 lukem #include <sys/cdefs.h> 41 1.174 rillig __RCSID("$NetBSD: pr_comment.c,v 1.174 2025/01/04 10:28:08 rillig Exp $"); 42 1.1 cgd 43 1.11 kamil #include <string.h> 44 1.12 rillig 45 1.11 kamil #include "indent.h" 46 1.12 rillig 47 1.14 rillig static void 48 1.71 rillig com_add_char(char ch) 49 1.14 rillig { 50 1.145 rillig buf_add_char(&com, ch); 51 1.71 rillig } 52 1.71 rillig 53 1.71 rillig static void 54 1.167 rillig com_add_star(void) 55 1.71 rillig { 56 1.154 rillig if (opt.star_comment_cont) 57 1.174 rillig buf_add_str(&com, " * "); 58 1.71 rillig } 59 1.71 rillig 60 1.77 rillig static bool 61 1.164 rillig fits_in_one_line(int max_line_length) 62 1.77 rillig { 63 1.173 rillig for (const char *start = in.p, *p = start; *p != '\n'; p++) { 64 1.145 rillig if (p[0] == '*' && p[1] == '/') { 65 1.173 rillig while (p - in.p >= 2 66 1.155 rillig && ch_isblank(p[-1]) 67 1.155 rillig && ch_isblank(p[-2])) 68 1.155 rillig p--; 69 1.164 rillig int ind = ind_add(ps.comment_ind + 3, 70 1.146 rillig start, (size_t)(p - start)); 71 1.164 rillig ind += p == start || ch_isblank(p[-1]) ? 2 : 3; 72 1.164 rillig return ind <= max_line_length; 73 1.145 rillig } 74 1.134 rillig } 75 1.145 rillig return false; 76 1.77 rillig } 77 1.77 rillig 78 1.168 rillig static bool 79 1.168 rillig is_block_comment(void) 80 1.168 rillig { 81 1.173 rillig const char *p = in.p; 82 1.168 rillig while (*p == '*') 83 1.168 rillig p++; 84 1.168 rillig return *p == '\n'; 85 1.168 rillig } 86 1.168 rillig 87 1.95 rillig static void 88 1.164 rillig analyze_comment(bool *p_may_wrap, bool *p_delim, int *p_line_length) 89 1.1 cgd { 90 1.145 rillig bool may_wrap = true; 91 1.167 rillig bool delim = false; // only relevant if may_wrap 92 1.145 rillig int ind; 93 1.145 rillig int line_length = opt.max_line_length; 94 1.145 rillig 95 1.173 rillig if (in.p - in.line.s == 2 && !opt.format_col1_comments) { 96 1.145 rillig may_wrap = false; 97 1.145 rillig ind = 0; 98 1.145 rillig } else { 99 1.173 rillig if (in.p[0] == '-' || in.p[0] == '*' || 100 1.151 rillig token.s[token.len - 1] == '/' || 101 1.173 rillig (in.p[0] == '\n' && !opt.format_block_comments)) 102 1.145 rillig may_wrap = false; 103 1.145 rillig 104 1.145 rillig if (com.len > 0) 105 1.145 rillig output_line(); 106 1.145 rillig if (lab.len == 0 && code.len == 0) { 107 1.170 rillig if (is_block_comment()) 108 1.170 rillig out.line_kind = lk_block_comment; 109 1.146 rillig ind = (ps.ind_level - opt.unindent_displace) 110 1.146 rillig * opt.indent_size; 111 1.145 rillig if (ind <= 0) 112 1.145 rillig ind = opt.format_col1_comments ? 0 : 1; 113 1.145 rillig line_length = opt.block_comment_max_line_length; 114 1.173 rillig if (may_wrap && in.p[0] == '\n') 115 1.157 rillig delim = true; 116 1.161 rillig if (may_wrap && opt.comment_delimiter_on_blank_line) 117 1.157 rillig delim = true; 118 1.145 rillig } else { 119 1.167 rillig int min_ind = code.len > 0 120 1.151 rillig ? ind_add(compute_code_indent(), code.s, code.len) 121 1.151 rillig : ind_add(compute_label_indent(), lab.s, lab.len); 122 1.145 rillig 123 1.159 rillig ind = ps.line_has_decl || ps.ind_level == 0 124 1.146 rillig ? opt.decl_comment_column - 1 125 1.146 rillig : opt.comment_column - 1; 126 1.167 rillig if (ind <= min_ind) 127 1.167 rillig ind = next_tab(min_ind); 128 1.145 rillig if (ind + 25 > line_length) 129 1.145 rillig line_length = ind + 25; 130 1.145 rillig } 131 1.11 kamil } 132 1.56 rillig 133 1.145 rillig if (!may_wrap) { 134 1.145 rillig /* Find out how much indentation there was originally, because 135 1.149 rillig * that much will have to be ignored by output_line. */ 136 1.173 rillig size_t len = (size_t)(in.p - 2 - in.line.s); 137 1.173 rillig ps.comment_shift = -ind_add(0, in.line.s, len); 138 1.19 rillig } else { 139 1.164 rillig ps.comment_shift = 0; 140 1.173 rillig if (!(in.p[0] == '\t' && !ch_isblank(in.p[1]))) 141 1.173 rillig while (ch_isblank(in.p[0])) 142 1.173 rillig in.p++; 143 1.145 rillig } 144 1.34 rillig 145 1.164 rillig ps.comment_ind = ind; 146 1.152 rillig *p_may_wrap = may_wrap; 147 1.152 rillig *p_delim = delim; 148 1.152 rillig *p_line_length = line_length; 149 1.152 rillig } 150 1.152 rillig 151 1.152 rillig static void 152 1.164 rillig copy_comment_start(bool may_wrap, bool *delim, int line_length) 153 1.152 rillig { 154 1.166 rillig ps.comment_cont = false; 155 1.168 rillig buf_add_chars(&com, token.s, token.len); // "/*" or "//" 156 1.145 rillig 157 1.156 rillig if (may_wrap) { 158 1.173 rillig if (!ch_isblank(in.p[0])) 159 1.156 rillig com_add_char(' '); 160 1.145 rillig 161 1.164 rillig if (*delim && fits_in_one_line(line_length)) 162 1.156 rillig *delim = false; 163 1.156 rillig if (*delim) { 164 1.156 rillig output_line(); 165 1.167 rillig com_add_star(); 166 1.156 rillig } 167 1.11 kamil } 168 1.95 rillig } 169 1.95 rillig 170 1.95 rillig static void 171 1.152 rillig copy_comment_wrap_text(int line_length, ssize_t *last_blank) 172 1.95 rillig { 173 1.167 rillig int ind = ind_add(ps.comment_ind, com.s, com.len); 174 1.152 rillig for (;;) { 175 1.152 rillig char ch = inp_next(); 176 1.152 rillig if (ch_isblank(ch)) 177 1.152 rillig *last_blank = (ssize_t)com.len; 178 1.152 rillig com_add_char(ch); 179 1.167 rillig ind++; 180 1.173 rillig if (memchr("*\n\r\t", in.p[0], 5) != NULL) 181 1.152 rillig break; 182 1.167 rillig if (ind >= line_length && *last_blank != -1) 183 1.152 rillig break; 184 1.152 rillig } 185 1.99 rillig 186 1.167 rillig if (ind <= line_length) 187 1.152 rillig return; 188 1.152 rillig if (ch_isspace(com.s[com.len - 1])) 189 1.152 rillig return; 190 1.145 rillig 191 1.168 rillig if (*last_blank == -1) { /* only a single word in this line */ 192 1.152 rillig output_line(); 193 1.167 rillig com_add_star(); 194 1.152 rillig return; 195 1.152 rillig } 196 1.101 rillig 197 1.167 rillig // Move the overlong word to the next line. 198 1.167 rillig const char *last_word = com.s + *last_blank + 1; 199 1.152 rillig size_t last_word_len = com.len - (size_t)(*last_blank + 1); 200 1.152 rillig com.len = (size_t)*last_blank; 201 1.167 rillig buf_terminate(&com); 202 1.152 rillig output_line(); 203 1.167 rillig com_add_star(); 204 1.152 rillig 205 1.167 rillig /* Assume that output_line and com_add_delim left the "unused" part of 206 1.167 rillig * the now truncated buffer beyond com.s + com.len as-is. */ 207 1.167 rillig memmove(com.s + com.len, last_word, last_word_len); 208 1.152 rillig com.len += last_word_len; 209 1.167 rillig buf_terminate(&com); 210 1.152 rillig *last_blank = -1; 211 1.152 rillig } 212 1.145 rillig 213 1.167 rillig /* In a comment that is re-wrapped, handle a single newline character. */ 214 1.152 rillig static bool 215 1.164 rillig copy_comment_wrap_newline(ssize_t *last_blank, bool seen_newline) 216 1.152 rillig { 217 1.152 rillig *last_blank = -1; 218 1.164 rillig if (seen_newline) { 219 1.152 rillig if (com.len > 3) { 220 1.152 rillig output_line(); 221 1.167 rillig com_add_star(); 222 1.152 rillig } 223 1.152 rillig output_line(); 224 1.167 rillig com_add_star(); 225 1.152 rillig } else { 226 1.152 rillig if (!(com.len > 0 && ch_isblank(com.s[com.len - 1]))) 227 1.152 rillig com_add_char(' '); 228 1.152 rillig *last_blank = (int)com.len - 1; 229 1.152 rillig } 230 1.173 rillig in.token_end_line++; 231 1.145 rillig 232 1.152 rillig /* flush any blanks and/or tabs at start of next line */ 233 1.153 rillig inp_skip(); /* '\n' */ 234 1.173 rillig while (ch_isblank(in.p[0])) 235 1.173 rillig in.p++; 236 1.173 rillig if (in.p[0] == '*' && in.p[1] == '/') 237 1.153 rillig return false; 238 1.173 rillig if (in.p[0] == '*') { 239 1.173 rillig in.p++; 240 1.173 rillig while (ch_isblank(in.p[0])) 241 1.173 rillig in.p++; 242 1.153 rillig } 243 1.145 rillig 244 1.152 rillig return true; 245 1.152 rillig } 246 1.145 rillig 247 1.152 rillig static void 248 1.152 rillig copy_comment_wrap_finish(int line_length, bool delim) 249 1.152 rillig { 250 1.152 rillig if (delim) { 251 1.152 rillig if (com.len > 3) 252 1.152 rillig output_line(); 253 1.168 rillig buf_clear(&com); 254 1.152 rillig } else { 255 1.152 rillig size_t len = com.len; 256 1.167 rillig // XXX: This loop differs from the one below. 257 1.152 rillig while (ch_isblank(com.s[len - 1])) 258 1.152 rillig len--; 259 1.167 rillig if (ind_add(ps.comment_ind, com.s, len) + 3 > line_length) 260 1.152 rillig output_line(); 261 1.152 rillig } 262 1.145 rillig 263 1.155 rillig while (com.len >= 2 264 1.155 rillig && ch_isblank(com.s[com.len - 1]) 265 1.155 rillig && ch_isblank(com.s[com.len - 2])) 266 1.155 rillig com.len--; 267 1.160 rillig buf_terminate(&com); 268 1.155 rillig 269 1.173 rillig in.p += 2; 270 1.154 rillig if (com.len > 0 && ch_isblank(com.s[com.len - 1])) 271 1.174 rillig buf_add_str(&com, "*/"); 272 1.154 rillig else 273 1.174 rillig buf_add_str(&com, " */"); 274 1.152 rillig } 275 1.145 rillig 276 1.152 rillig static void 277 1.152 rillig copy_comment_wrap(int line_length, bool delim) 278 1.152 rillig { 279 1.152 rillig ssize_t last_blank = -1; /* index of the last blank in 'com' */ 280 1.163 rillig bool seen_newline = false; 281 1.145 rillig 282 1.152 rillig for (;;) { 283 1.173 rillig if (in.p[0] == '\n') { 284 1.152 rillig if (had_eof) 285 1.152 rillig goto unterminated_comment; 286 1.163 rillig if (!copy_comment_wrap_newline(&last_blank, 287 1.165 rillig seen_newline)) 288 1.164 rillig break; 289 1.164 rillig seen_newline = true; 290 1.173 rillig } else if (in.p[0] == '*' && in.p[1] == '/') 291 1.164 rillig break; 292 1.163 rillig else { 293 1.152 rillig copy_comment_wrap_text(line_length, &last_blank); 294 1.163 rillig seen_newline = false; 295 1.163 rillig } 296 1.152 rillig } 297 1.145 rillig 298 1.152 rillig copy_comment_wrap_finish(line_length, delim); 299 1.152 rillig return; 300 1.152 rillig 301 1.152 rillig unterminated_comment: 302 1.173 rillig in.token_start_line = in.token_end_line; 303 1.152 rillig diag(1, "Unterminated comment"); 304 1.152 rillig output_line(); 305 1.99 rillig } 306 1.99 rillig 307 1.99 rillig static void 308 1.103 rillig copy_comment_nowrap(void) 309 1.99 rillig { 310 1.151 rillig char kind = token.s[token.len - 1]; 311 1.150 rillig 312 1.145 rillig for (;;) { 313 1.173 rillig if (in.p[0] == '\n') { 314 1.150 rillig if (kind == '/') 315 1.145 rillig return; 316 1.145 rillig 317 1.145 rillig if (had_eof) { 318 1.173 rillig in.token_start_line = in.token_end_line; 319 1.145 rillig diag(1, "Unterminated comment"); 320 1.145 rillig output_line(); 321 1.145 rillig return; 322 1.145 rillig } 323 1.145 rillig 324 1.145 rillig output_line(); 325 1.173 rillig in.token_end_line++; 326 1.145 rillig inp_skip(); 327 1.145 rillig continue; 328 1.145 rillig } 329 1.56 rillig 330 1.173 rillig if (kind == '*' && in.p[0] == '*' && in.p[1] == '/') { 331 1.173 rillig com_add_char(*in.p++); 332 1.173 rillig com_add_char(*in.p++); 333 1.171 rillig return; 334 1.171 rillig } 335 1.171 rillig 336 1.173 rillig com_add_char(*in.p++); 337 1.104 rillig } 338 1.1 cgd } 339 1.95 rillig 340 1.95 rillig void 341 1.95 rillig process_comment(void) 342 1.95 rillig { 343 1.145 rillig bool may_wrap, delim; 344 1.164 rillig int line_length; 345 1.95 rillig 346 1.164 rillig analyze_comment(&may_wrap, &delim, &line_length); 347 1.164 rillig copy_comment_start(may_wrap, &delim, line_length); 348 1.145 rillig if (may_wrap) 349 1.145 rillig copy_comment_wrap(line_length, delim); 350 1.145 rillig else 351 1.145 rillig copy_comment_nowrap(); 352 1.95 rillig } 353