Annotation of src/usr.bin/indent/pr_comment.c, Revision 1.127
1.127 ! rillig 1: /* $NetBSD: pr_comment.c,v 1.126 2021/11/27 18:37:17 rillig Exp $ */
1.4 tls 2:
1.11 kamil 3: /*-
4: * SPDX-License-Identifier: BSD-4-Clause
5: *
6: * Copyright (c) 1985 Sun Microsystems, Inc.
1.5 mrg 7: * Copyright (c) 1980, 1993
8: * The Regents of the University of California. All rights reserved.
1.1 cgd 9: * All rights reserved.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the University of
22: * California, Berkeley and its contributors.
23: * 4. Neither the name of the University nor the names of its contributors
24: * may be used to endorse or promote products derived from this software
25: * without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37: * SUCH DAMAGE.
38: */
39:
1.11 kamil 40: #if 0
41: static char sccsid[] = "@(#)pr_comment.c 8.1 (Berkeley) 6/6/93";
42: #endif
43:
1.6 lukem 44: #include <sys/cdefs.h>
1.11 kamil 45: #if defined(__NetBSD__)
1.127 ! rillig 46: __RCSID("$NetBSD: pr_comment.c,v 1.126 2021/11/27 18:37:17 rillig Exp $");
1.11 kamil 47: #elif defined(__FreeBSD__)
48: __FBSDID("$FreeBSD: head/usr.bin/indent/pr_comment.c 334927 2018-06-10 16:44:18Z pstef $");
49: #endif
1.1 cgd 50:
1.68 rillig 51: #include <assert.h>
1.1 cgd 52: #include <stdio.h>
1.11 kamil 53: #include <string.h>
1.12 rillig 54:
1.11 kamil 55: #include "indent.h"
1.12 rillig 56:
1.14 rillig 57: static void
1.71 rillig 58: com_add_char(char ch)
1.14 rillig 59: {
1.89 rillig 60: if (1 >= com.l - com.e)
1.71 rillig 61: buf_expand(&com, 1);
62: *com.e++ = ch;
63: }
64:
65: static void
66: com_add_delim(void)
67: {
68: if (!opt.star_comment_cont)
69: return;
1.125 rillig 70: const char *delim = " * ";
71: buf_add_range(&com, delim, delim + 3);
1.71 rillig 72: }
73:
74: static void
75: com_terminate(void)
76: {
1.89 rillig 77: if (1 >= com.l - com.e)
1.71 rillig 78: buf_expand(&com, 1);
79: *com.e = '\0';
1.14 rillig 80: }
81:
1.77 rillig 82: static bool
1.124 rillig 83: fits_in_one_line(int com_ind, int max_line_length)
1.77 rillig 84: {
1.120 rillig 85: for (const char *p = inp_p(); *p != '\n'; p++) {
1.77 rillig 86: assert(*p != '\0');
1.120 rillig 87: assert(inp_line_end() - p >= 2);
1.77 rillig 88: if (!(p[0] == '*' && p[1] == '/'))
89: continue;
90:
1.124 rillig 91: int len = ind_add(com_ind + 3, inp_p(), p);
1.90 rillig 92: len += ch_isblank(p[-1]) ? 2 : 3;
1.91 rillig 93: return len <= max_line_length;
1.77 rillig 94: }
95: return false;
96: }
97:
1.95 rillig 98: static void
1.109 rillig 99: analyze_comment(bool *p_may_wrap, bool *p_break_delim,
100: int *p_adj_max_line_length)
1.1 cgd 101: {
1.47 rillig 102: int adj_max_line_length; /* Adjusted max_line_length for comments that
103: * spill over the right margin */
1.44 rillig 104: bool break_delim = opt.comment_delimiter_on_blankline;
1.78 rillig 105: int com_ind;
1.11 kamil 106:
1.26 rillig 107: adj_max_line_length = opt.max_line_length;
1.75 rillig 108: bool may_wrap = true;
1.11 kamil 109:
1.93 rillig 110: if (ps.curr_col_1 && !opt.format_col1_comments) {
1.75 rillig 111: may_wrap = false;
1.11 kamil 112: break_delim = false;
1.78 rillig 113: com_ind = 0;
1.56 rillig 114:
1.19 rillig 115: } else {
1.119 rillig 116: if (inp_peek() == '-' || inp_peek() == '*' ||
1.117 rillig 117: token.e[-1] == '/' ||
1.119 rillig 118: (inp_peek() == '\n' && !opt.format_block_comments)) {
1.75 rillig 119: may_wrap = false;
1.11 kamil 120: break_delim = false;
121: }
1.56 rillig 122:
1.122 rillig 123: /*
124: * XXX: This condition looks suspicious since it ignores the case
125: * where the end of the previous comment is still in 'com'.
126: *
127: * See test token_comment.c, keyword 'analyze_comment'.
128: */
1.45 rillig 129: if (lab.s == lab.e && code.s == code.e) {
1.116 rillig 130: adj_max_line_length = opt.block_comment_max_line_length;
1.78 rillig 131: com_ind = (ps.ind_level - opt.unindent_displace) * opt.indent_size;
132: if (com_ind <= 0)
133: com_ind = opt.format_col1_comments ? 0 : 1;
1.56 rillig 134:
1.19 rillig 135: } else {
1.33 rillig 136: break_delim = false;
1.34 rillig 137:
1.112 rillig 138: int target_ind = code.s != code.e
139: ? ind_add(compute_code_indent(), code.s, code.e)
140: : ind_add(compute_label_indent(), lab.s, lab.e);
1.34 rillig 141:
1.78 rillig 142: com_ind = ps.decl_on_line || ps.ind_level == 0
1.60 rillig 143: ? opt.decl_comment_column - 1 : opt.comment_column - 1;
1.78 rillig 144: if (com_ind <= target_ind)
145: com_ind = next_tab(target_ind);
1.79 rillig 146: if (com_ind + 25 > adj_max_line_length)
147: adj_max_line_length = com_ind + 25;
1.11 kamil 148: }
149: }
1.56 rillig 150:
1.78 rillig 151: ps.com_ind = com_ind;
152:
1.75 rillig 153: if (!may_wrap) {
1.6 lukem 154: /*
1.11 kamil 155: * Find out how much indentation there was originally, because that
1.126 rillig 156: * much will have to be ignored by output_complete_line.
1.25 rillig 157: */
1.120 rillig 158: const char *start = inp_line_start();
159: ps.n_comment_delta = -ind_add(0, start, inp_p() - 2);
1.19 rillig 160: } else {
1.11 kamil 161: ps.n_comment_delta = 0;
1.119 rillig 162: while (ch_isblank(inp_peek()))
1.120 rillig 163: inp_skip();
1.11 kamil 164: }
1.56 rillig 165:
1.11 kamil 166: ps.comment_delta = 0;
1.71 rillig 167: com_add_char('/');
168: com_add_char(token.e[-1]); /* either '*' or '/' */
1.116 rillig 169:
170: /* TODO: Maybe preserve a single '\t' as well. */
1.119 rillig 171: if (inp_peek() != ' ' && may_wrap)
1.71 rillig 172: com_add_char(' ');
1.11 kamil 173:
1.124 rillig 174: if (break_delim && fits_in_one_line(com_ind, adj_max_line_length))
1.77 rillig 175: break_delim = false;
1.1 cgd 176:
1.11 kamil 177: if (break_delim) {
1.84 rillig 178: if (opt.blanklines_before_block_comments &&
1.88 rillig 179: ps.prev_token != lsym_lbrace)
1.127 ! rillig 180: out.blank_line_before = true;
1.126 rillig 181: output_line();
1.75 rillig 182: com_add_delim();
1.11 kamil 183: }
184:
1.95 rillig 185: *p_adj_max_line_length = adj_max_line_length;
186: *p_break_delim = break_delim;
187: *p_may_wrap = may_wrap;
188: }
189:
1.110 rillig 190: /*
191: * Copy characters from 'inp' to 'com'. Try to keep comments from going over
192: * the maximum line length. To do that, remember where the last blank, tab, or
193: * newline was. When a line is filled, print up to the last blank and continue
194: * copying.
195: */
1.95 rillig 196: static void
1.99 rillig 197: copy_comment_wrap(int adj_max_line_length, bool break_delim)
1.95 rillig 198: {
1.99 rillig 199: ssize_t last_blank = -1; /* index of the last blank in com.buf */
200:
201: for (;;) {
1.119 rillig 202: switch (inp_peek()) {
1.99 rillig 203: case '\f':
1.126 rillig 204: output_line_ff();
1.101 rillig 205: last_blank = -1;
206: com_add_delim();
1.120 rillig 207: inp_skip();
1.119 rillig 208: while (ch_isblank(inp_peek()))
1.120 rillig 209: inp_skip();
1.99 rillig 210: break;
211:
212: case '\n':
213: if (had_eof) {
214: diag(1, "Unterminated comment");
1.126 rillig 215: output_line();
1.99 rillig 216: return;
217: }
218:
219: last_blank = -1;
1.101 rillig 220: if (ps.next_col_1) {
1.99 rillig 221: if (com.s == com.e)
1.116 rillig 222: com_add_char(' '); /* force empty line of output */
1.101 rillig 223: if (com.e - com.s > 3) {
1.126 rillig 224: output_line();
1.99 rillig 225: com_add_delim();
226: }
1.126 rillig 227: output_line();
1.101 rillig 228: com_add_delim();
1.99 rillig 229:
230: } else {
231: ps.next_col_1 = true;
1.114 rillig 232: if (!(com.e > com.s && ch_isblank(com.e[-1])))
1.99 rillig 233: com_add_char(' ');
234: last_blank = com.e - 1 - com.buf;
235: }
236: ++line_no;
1.101 rillig 237:
238: bool skip_asterisk = true;
239: do { /* flush any blanks and/or tabs at start of
1.99 rillig 240: * next line */
1.101 rillig 241: inp_skip();
1.119 rillig 242: if (inp_peek() == '*' && skip_asterisk) {
1.101 rillig 243: skip_asterisk = false;
1.99 rillig 244: inp_skip();
1.119 rillig 245: if (inp_peek() == '/')
1.101 rillig 246: goto end_of_comment;
247: }
1.119 rillig 248: } while (ch_isblank(inp_peek()));
1.101 rillig 249:
1.99 rillig 250: break; /* end of case for newline */
251:
252: case '*':
253: inp_skip();
1.119 rillig 254: if (inp_peek() == '/') {
1.99 rillig 255: end_of_comment:
256: inp_skip();
257:
258: if (break_delim) {
1.116 rillig 259: if (com.e - com.s > 3)
1.126 rillig 260: output_line();
1.99 rillig 261: else
1.113 rillig 262: com.e = com.s;
1.99 rillig 263: com_add_char(' ');
264: }
265:
1.114 rillig 266: if (!(com.e > com.s && ch_isblank(com.e[-1])))
1.99 rillig 267: com_add_char(' ');
1.111 rillig 268: com_add_char('*');
269: com_add_char('/');
1.99 rillig 270: com_terminate();
271: return;
272:
273: } else /* handle isolated '*' */
274: com_add_char('*');
275: break;
276:
277: default: /* we have a random char */
278: ;
279: int now_len = ind_add(ps.com_ind, com.s, com.e);
280: for (;;) {
281: char ch = inp_next();
282: if (ch_isblank(ch))
283: last_blank = com.e - com.buf;
284: com_add_char(ch);
285: now_len++;
1.119 rillig 286: if (memchr("*\n\r\b\t", inp_peek(), 6) != NULL)
1.99 rillig 287: break;
288: if (now_len >= adj_max_line_length && last_blank != -1)
289: break;
290: }
291:
292: ps.next_col_1 = false;
293:
1.101 rillig 294: if (now_len <= adj_max_line_length)
1.99 rillig 295: break;
1.121 rillig 296: if (ch_isspace(com.e[-1]))
1.99 rillig 297: break;
298:
299: if (last_blank == -1) { /* only a single word in this line */
1.126 rillig 300: output_line();
1.99 rillig 301: com_add_delim();
302: break;
303: }
304:
305: const char *last_word_s = com.buf + last_blank + 1;
306: size_t last_word_len = (size_t)(com.e - last_word_s);
307: com.e = com.buf + last_blank;
1.126 rillig 308: output_line();
1.99 rillig 309: com_add_delim();
310:
311: memcpy(com.e, last_word_s, last_word_len);
312: com.e += last_word_len;
313: last_blank = -1;
314: }
315: }
316: }
317:
318: static void
1.103 rillig 319: copy_comment_nowrap(void)
1.99 rillig 320: {
1.81 rillig 321: for (;;) {
1.119 rillig 322: if (inp_peek() == '\n') {
1.62 rillig 323: if (token.e[-1] == '/')
1.105 rillig 324: goto finish;
1.56 rillig 325:
1.54 rillig 326: if (had_eof) {
1.67 rillig 327: diag(1, "Unterminated comment");
1.126 rillig 328: output_line();
1.11 kamil 329: return;
330: }
1.56 rillig 331:
1.100 rillig 332: if (com.s == com.e)
333: com_add_char(' '); /* force output of an empty line */
1.126 rillig 334: output_line();
1.54 rillig 335: ++line_no;
1.100 rillig 336: inp_skip();
1.104 rillig 337: continue;
338: }
1.1 cgd 339:
1.106 rillig 340: com_add_char(inp_next());
1.107 rillig 341: if (com.e[-2] == '*' && com.e[-1] == '/' && token.e[-1] == '*')
1.106 rillig 342: goto finish;
1.11 kamil 343: }
1.105 rillig 344:
345: finish:
346: com_terminate();
1.1 cgd 347: }
1.95 rillig 348:
349: /*
350: * Scan, reformat and output a single comment, which is either a block comment
351: * starting with '/' '*' or an end-of-line comment starting with '//'.
352: */
353: void
354: process_comment(void)
355: {
1.109 rillig 356: int adj_max_line_length;
357: bool may_wrap, break_delim;
1.95 rillig 358:
359: ps.just_saw_decl = 0;
360: ps.stats.comments++;
361:
1.109 rillig 362: int saved_just_saw_decl = ps.just_saw_decl;
363: analyze_comment(&may_wrap, &break_delim, &adj_max_line_length);
1.99 rillig 364: if (may_wrap)
1.100 rillig 365: copy_comment_wrap(adj_max_line_length, break_delim);
1.99 rillig 366: else
1.103 rillig 367: copy_comment_nowrap();
1.109 rillig 368: ps.just_saw_decl = saved_just_saw_decl;
1.95 rillig 369: }
CVSweb <webmaster@jp.NetBSD.org>