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