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 *
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
69static char sccsid[] = "@(#)pr_comment.c	8.1 (Berkeley) 6/6/93";
70#else
71__RCSID("$NetBSD: pr_comment.c,v 1.8 2003/06/19 15:45:22 christos 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
112void
113pr_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