xref: /netbsd-src/usr.bin/indent/pr_comment.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: pr_comment.c,v 1.8 2003/06/19 15:45:22 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
7  * Copyright (c) 1985 Sun Microsystems, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)pr_comment.c	8.1 (Berkeley) 6/6/93";
43 #else
44 __RCSID("$NetBSD: pr_comment.c,v 1.8 2003/06/19 15:45:22 christos Exp $");
45 #endif
46 #endif				/* not lint */
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <ctype.h>
51 #include "indent_globs.h"
52 
53 /*
54  * NAME:
55  *	pr_comment
56  *
57  * FUNCTION:
58  *	This routine takes care of scanning and printing comments.
59  *
60  * ALGORITHM:
61  *	1) Decide where the comment should be aligned, and if lines should
62  *	   be broken.
63  *	2) If lines should not be broken and filled, just copy up to end of
64  *	   comment.
65  *	3) If lines should be filled, then scan thru input_buffer copying
66  *	   characters to com_buf.  Remember where the last blank, tab, or
67  *	   newline was.  When line is filled, print up to last blank and
68  *	   continue copying.
69  *
70  * HISTORY:
71  *	November 1976	D A Willcox of CAC	Initial coding
72  *	12/6/76		D A Willcox of CAC	Modification to handle
73  *						UNIX-style comments
74  *
75  */
76 
77 /*
78  * this routine processes comments.  It makes an attempt to keep comments from
79  * going over the max line length.  If a line is too long, it moves everything
80  * from the last blank to the next comment line.  Blanks and tabs from the
81  * beginning of the input line are removed
82  */
83 
84 
85 void
86 pr_comment(void)
87 {
88 	int     now_col;	/* column we are in now */
89 	int     adj_max_col;	/* Adjusted max_col for when we decide to
90 				 * spill comments over the right margin */
91 	char   *last_bl;	/* points to the last blank in the output
92 				 * buffer */
93 	char   *t_ptr;		/* used for moving string */
94 	int     unix_comment;	/* tri-state variable used to decide if it is
95 				 * a unix-style comment. 0 means only blanks
96 				 * since start, 1 means regular style comment,
97 				 * 2 means unix style comment */
98 	int     break_delim = comment_delimiter_on_blankline;
99 	int     l_just_saw_decl = ps.just_saw_decl;
100 	/*
101          * int         ps.last_nl = 0;	/ * true iff the last significant thing
102          * weve seen is a newline
103          */
104 	int     one_liner = 1;	/* true iff this comment is a one-liner */
105 	adj_max_col = max_col;
106 	ps.just_saw_decl = 0;
107 	last_bl = 0;		/* no blanks found so far */
108 	ps.box_com = false;	/* at first, assume that we are not in a boxed
109 				 * comment or some other comment that should
110 				 * not be touched */
111 	++ps.out_coms;		/* keep track of number of comments */
112 	unix_comment = 1;	/* set flag to let us figure out if there is a
113 				 * unix-style comment ** DISABLED: use 0 to
114 				 * reenable this hack! */
115 
116 	/* Figure where to align and how to treat the comment */
117 
118 	if (ps.col_1 && !format_col1_comments) {	/* if comment starts in
119 							 * column 1 it should
120 							 * not be touched */
121 		ps.box_com = true;
122 		ps.com_col = 1;
123 	} else {
124 		if (*buf_ptr == '-' || *buf_ptr == '*' || *buf_ptr == '\n') {
125 			ps.box_com = true;	/* a comment with a '-', '*'
126 						 * or newline immediately
127 						 * after the start comment is
128 						 * assumed to be a boxed
129 						 * comment */
130 			break_delim = 0;
131 		}
132 		if ( /* ps.bl_line && */ (s_lab == e_lab) && (s_code == e_code)) {
133 			/* klg: check only if this line is blank */
134 			/*
135 		         * If this (*and previous lines are*) blank, dont put comment way
136 		         * out at left
137 		         */
138 			ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1;
139 			adj_max_col = block_comment_max_col;
140 			if (ps.com_col <= 1)
141 				ps.com_col = 1 + !format_col1_comments;
142 		} else {
143 			int     target_col;
144 			break_delim = 0;
145 			if (s_code != e_code)
146 				target_col = count_spaces(compute_code_target(), s_code);
147 			else {
148 				target_col = 1;
149 				if (s_lab != e_lab)
150 					target_col = count_spaces(compute_label_target(), s_lab);
151 			}
152 			ps.com_col = ps.decl_on_line || ps.ind_level == 0 ? ps.decl_com_ind : ps.com_ind;
153 			if (ps.com_col < target_col)
154 				ps.com_col = ((target_col + 7) & ~7) + 1;
155 			if (ps.com_col + 24 > adj_max_col)
156 				adj_max_col = ps.com_col + 24;
157 		}
158 	}
159 	if (ps.box_com) {
160 		buf_ptr[-2] = 0;
161 		ps.n_comment_delta = 1 - count_spaces(1, in_buffer);
162 		buf_ptr[-2] = '/';
163 	} else {
164 		ps.n_comment_delta = 0;
165 		while (*buf_ptr == ' ' || *buf_ptr == '\t')
166 			buf_ptr++;
167 	}
168 	ps.comment_delta = 0;
169 	*e_com++ = '/';		/* put '/' + '*' into buffer */
170 	*e_com++ = '*';
171 	if (*buf_ptr != ' ' && !ps.box_com)
172 		*e_com++ = ' ';
173 
174 	*e_com = '\0';
175 	if (troff) {
176 		now_col = 1;
177 		adj_max_col = 80;
178 	} else
179 		now_col = count_spaces(ps.com_col, s_com);	/* figure what column we
180 								 * would be in if we
181 								 * printed the comment
182 								 * now */
183 
184 	/* Start to copy the comment */
185 
186 	while (1) {		/* this loop will go until the comment is
187 				 * copied */
188 		if (!iscntrl((unsigned char)*buf_ptr) && *buf_ptr != '*')
189 			ps.last_nl = 0;
190 		CHECK_SIZE_COM;
191 		switch (*buf_ptr) {	/* this checks for various spcl cases */
192 		case 014:	/* check for a form feed */
193 			if (!ps.box_com) {	/* in a text comment, break
194 						 * the line here */
195 				ps.use_ff = true;
196 				/* fix so dump_line uses a form feed */
197 				dump_line();
198 				last_bl = 0;
199 				*e_com++ = ' ';
200 				*e_com++ = '*';
201 				*e_com++ = ' ';
202 				while (*++buf_ptr == ' ' || *buf_ptr == '\t');
203 			} else {
204 				if (++buf_ptr >= buf_end)
205 					fill_buffer();
206 				*e_com++ = 014;
207 			}
208 			break;
209 
210 		case '\n':
211 			if (had_eof) {	/* check for unexpected eof */
212 				printf("Unterminated comment\n");
213 				*e_com = '\0';
214 				dump_line();
215 				return;
216 			}
217 			one_liner = 0;
218 			if (ps.box_com || ps.last_nl) {	/* if this is a boxed
219 							 * comment, we dont
220 							 * ignore the newline */
221 				if (s_com == e_com) {
222 					*e_com++ = ' ';
223 					*e_com++ = ' ';
224 				}
225 				*e_com = '\0';
226 				if (!ps.box_com && e_com - s_com > 3) {
227 					if (break_delim == 1 && s_com[0] == '/'
228 					    && s_com[1] == '*' && s_com[2] == ' ') {
229 						char   *t = e_com;
230 						break_delim = 2;
231 						e_com = s_com + 2;
232 						*e_com = 0;
233 						if (blanklines_before_blockcomments)
234 							prefix_blankline_requested = 1;
235 						dump_line();
236 						e_com = t;
237 						s_com[0] = s_com[1] = s_com[2] = ' ';
238 					}
239 					dump_line();
240 					CHECK_SIZE_COM;
241 					*e_com++ = ' ';
242 					*e_com++ = ' ';
243 				}
244 				dump_line();
245 				now_col = ps.com_col;
246 			} else {
247 				ps.last_nl = 1;
248 				if (unix_comment != 1) {	/* we not are in
249 								 * unix_style comment */
250 					if (unix_comment == 0 && s_code == e_code) {
251 						/*
252 						 * if it is a UNIX-style comment, ignore the
253 						 * requirement that previous line be blank for
254 						 * unindention
255 						 */
256 						ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1;
257 						if (ps.com_col <= 1)
258 							ps.com_col = 2;
259 					}
260 					unix_comment = 2;	/* permanently remember
261 								 * that we are in this
262 								 * type of comment */
263 					dump_line();
264 					++line_no;
265 					now_col = ps.com_col;
266 					*e_com++ = ' ';
267 					/*
268 				         * fix so that the star at the start of the line will line
269 				         * up
270 				         */
271 					do	/* flush leading white space */
272 						if (++buf_ptr >= buf_end)
273 							fill_buffer();
274 					while (*buf_ptr == ' ' || *buf_ptr == '\t');
275 					break;
276 				}
277 				if (*(e_com - 1) == ' ' || *(e_com - 1) == '\t')
278 					last_bl = e_com - 1;
279 				/*
280 				 * if there was a space at the end of the last line, remember
281 				 * where it was
282 				 */
283 				else {	/* otherwise, insert one */
284 					last_bl = e_com;
285 					CHECK_SIZE_COM;
286 					*e_com++ = ' ';
287 					++now_col;
288 				}
289 			}
290 			++line_no;	/* keep track of input line number */
291 			if (!ps.box_com) {
292 				int     nstar = 1;
293 				do {	/* flush any blanks and/or tabs at
294 					 * start of next line */
295 					if (++buf_ptr >= buf_end)
296 						fill_buffer();
297 					if (*buf_ptr == '*' && --nstar >= 0) {
298 						if (++buf_ptr >= buf_end)
299 							fill_buffer();
300 						if (*buf_ptr == '/')
301 							goto end_of_comment;
302 					}
303 				} while (*buf_ptr == ' ' || *buf_ptr == '\t');
304 			} else
305 				if (++buf_ptr >= buf_end)
306 					fill_buffer();
307 			break;	/* end of case for newline */
308 
309 		case '*':	/* must check for possibility of being at end
310 				 * of comment */
311 			if (++buf_ptr >= buf_end)	/* get to next char
312 							 * after * */
313 				fill_buffer();
314 
315 			if (unix_comment == 0)	/* set flag to show we are not
316 						 * in unix-style comment */
317 				unix_comment = 1;
318 
319 			if (*buf_ptr == '/') {	/* it is the end!!! */
320 		end_of_comment:
321 				if (++buf_ptr >= buf_end)
322 					fill_buffer();
323 
324 				if (*(e_com - 1) != ' ' && !ps.box_com) {	/* insure blank before
325 										 * end */
326 					*e_com++ = ' ';
327 					++now_col;
328 				}
329 				if (break_delim == 1 && !one_liner && s_com[0] == '/'
330 				    && s_com[1] == '*' && s_com[2] == ' ') {
331 					char   *t = e_com;
332 					break_delim = 2;
333 					e_com = s_com + 2;
334 					*e_com = 0;
335 					if (blanklines_before_blockcomments)
336 						prefix_blankline_requested = 1;
337 					dump_line();
338 					e_com = t;
339 					s_com[0] = s_com[1] = s_com[2] = ' ';
340 				}
341 				if (break_delim == 2 && e_com > s_com + 3
342 				     /* now_col > adj_max_col - 2 && !ps.box_com */ ) {
343 					*e_com = '\0';
344 					dump_line();
345 					now_col = ps.com_col;
346 				}
347 				CHECK_SIZE_COM;
348 				*e_com++ = '*';
349 				*e_com++ = '/';
350 				*e_com = '\0';
351 				ps.just_saw_decl = l_just_saw_decl;
352 				return;
353 			} else {/* handle isolated '*' */
354 				*e_com++ = '*';
355 				++now_col;
356 			}
357 			break;
358 		default:	/* we have a random char */
359 			if (unix_comment == 0 && *buf_ptr != ' ' && *buf_ptr != '\t')
360 				unix_comment = 1;	/* we are not in
361 							 * unix-style comment */
362 
363 			*e_com = *buf_ptr++;
364 			if (buf_ptr >= buf_end)
365 				fill_buffer();
366 
367 			if (*e_com == '\t')	/* keep track of column */
368 				now_col = ((now_col - 1) & tabmask) + tabsize + 1;
369 			else
370 				if (*e_com == '\b')	/* this is a backspace */
371 					--now_col;
372 				else
373 					++now_col;
374 
375 			if (*e_com == ' ' || *e_com == '\t')
376 				last_bl = e_com;
377 			/* remember we saw a blank */
378 
379 			++e_com;
380 			if (now_col > adj_max_col && !ps.box_com && unix_comment == 1
381 				&& !iscntrl((unsigned char)e_com[-1])
382 				&& !isblank((unsigned char)e_com[-1])) {
383 				/*
384 				 * the comment is too long, it must be broken up
385 				 */
386 				if (break_delim == 1 && s_com[0] == '/'
387 				    && s_com[1] == '*' && s_com[2] == ' ') {
388 					char   *t = e_com;
389 					break_delim = 2;
390 					e_com = s_com + 2;
391 					*e_com = 0;
392 					if (blanklines_before_blockcomments)
393 						prefix_blankline_requested = 1;
394 					dump_line();
395 					e_com = t;
396 					s_com[0] = s_com[1] = s_com[2] = ' ';
397 				}
398 				if (last_bl == 0) {	/* we have seen no
399 							 * blanks */
400 					last_bl = e_com;	/* fake it */
401 					*e_com++ = ' ';
402 				}
403 				*e_com = '\0';	/* print what we have */
404 				*last_bl = '\0';
405 				while (last_bl > s_com && iscntrl((unsigned char)last_bl[-1]) )
406 					*--last_bl = 0;
407 				e_com = last_bl;
408 				dump_line();
409 
410 				*e_com++ = ' ';	/* add blanks for continuation */
411 				*e_com++ = ' ';
412 				*e_com++ = ' ';
413 
414 				t_ptr = last_bl + 1;
415 				last_bl = 0;
416 				if (t_ptr >= e_com) {
417 					while (*t_ptr == ' ' || *t_ptr == '\t')
418 						t_ptr++;
419 					while (*t_ptr != '\0') {	/* move unprinted part
420 									 * of comment down in
421 									 * buffer */
422 						if (*t_ptr == ' ' || *t_ptr == '\t')
423 							last_bl = e_com;
424 						*e_com++ = *t_ptr++;
425 					}
426 				}
427 				*e_com = '\0';
428 				now_col = count_spaces(ps.com_col, s_com);	/* recompute current
429 										 * position */
430 			}
431 			break;
432 		}
433 	}
434 }
435