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