1 /** \file
2 * Copyright (c) 2015 Tim Hentenaar. All Rights Reserved.<br>
3 * Copyright (c) 2002 D.Ingamells
4 * Copyright (c) 1999, 2000 Carlo Wood. All rights reserved. <br>
5 * Copyright (c) 1994, 1996, 1997 Joseph Arceneaux. All rights reserved. <br>
6 * Copyright (c) 1992, 2002, 2008, 2015 Free Software Foundation, Inc. All rights reserved. <br>
7 *
8 * Copyright (c) 1980 The Regents of the University of California. <br>
9 * Copyright (c) 1976 Board of Trustees of the University of Illinois. All rights reserved.
10 * Copyright (c) 1985 Sun Microsystems, Inc.
11 * All rights reserved.<br>
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * - 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * - 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * - 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.<br>
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * This program is free software; you can redistribute it and/or
38 * modify it under the terms of the GNU General Public License
39 * as published by the Free Software Foundation; either version 3
40 * of the License, or (at your option) any later version.
41 *
42 * This program is distributed in the hope that it will be useful,
43 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 * GNU General Public License for more details.
46 *
47 * You should have received a copy of the GNU General Public License
48 * along with this program. If not, see <http://www.gnu.org/licenses/>.
49 *
50 * File: output.c
51 * Purpose: Interface to the output file for the indent tool.
52 *
53 * History:
54 * - 2002-03-04 D.Ingamells Creation.
55 * - 2002-11-10 Cristalle Azundris Sabon <cristalle@azundris.com>
56 * Added --preprocessor-indentation (ppi) if set, will indent nested
57 * preprocessor-statements with n spaces per level. overrides -lps.
58 * -2007-11-11 Jean-Christophe Dubois <jcd@tribudubois.net>
59 * Added --indent-label and --linux-style options.
60 */
61
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <sys/types.h>
65 #include <utime.h>
66 #include <time.h>
67 #include <sys/stat.h>
68
69 #include "indent.h"
70 #include "sys.h"
71 #include "globs.h"
72 #include "code_io.h"
73 #include "output.h"
74
75 RCSTAG_CC ("$Id$");
76
77 FILE * output = NULL;
78 static BOOLEAN inhibited = 0;
79 static buf_break_st_ty * buf_break_list = NULL;
80 buf_break_st_ty * buf_break = NULL;
81
82 int out_lines = 0; /*!< used in output.c indent.c */
83 int com_lines = 0; /*!< used in output.c indent.c comments.c */
84
85 int prev_target_col_break = 0;
86 int buf_break_used = 0;
87 int preproc_indent = 0;
88
89 /**
90 * Returns `true' when `b1' is a better place to break the code than `b2'.
91 * `b1' must be newer.
92 *
93 * When `lineup_to_parens' is true, do not break more then 1 level deeper
94 * unless that doesn't cost us "too much" indentation.
95 * What is "too much" is determined in a fuzzy way as follows:
96 * Consider the example,
97 * while (!(!(!(!(!(!(mask
98 * || (((a_very_long_expression_that_cant_be_broken
99 * here we prefer to break after `mask' instead of after `while'.
100 * This is because the `target_col' is pretty close to the break point
101 * of the `while': "mask"->target_col - "while"->col == 15 == "mask"->level * 2 + 1.
102 */
103
better_break(buf_break_st_ty * b1,const buf_break_st_ty * b2)104 static BOOLEAN better_break (
105 buf_break_st_ty *b1,
106 const buf_break_st_ty *b2)
107 {
108 static int first_level;
109 BOOLEAN is_better;
110
111 if (!b2)
112 {
113 first_level = b1->level;
114 b1->first_level = first_level;
115 is_better = true;
116 }
117 else
118 {
119 if (b2->target_col >= b2->col + 1)
120 {
121 is_better = true;
122 }
123 else if (settings.honour_newlines && b2->priority_newline)
124 {
125 is_better = false;
126 }
127 else if (settings.honour_newlines && b1->priority_newline)
128 {
129 is_better = true;
130 }
131 else
132 {
133 int only_parens_till_b2 = 0;
134
135 is_better = (b1->priority > b2->priority);
136
137 if (is_better)
138 {
139 char *p;
140
141 for (p = &s_code[b2->offset]; p >= s_code; --p)
142 {
143 if (*p == '!')
144 {
145 --p;
146 }
147
148 if (*p != '(')
149 {
150 break;
151 }
152 }
153
154 if (p < s_code)
155 {
156 only_parens_till_b2 = 1;
157 }
158 }
159
160 if (settings.lineup_to_parens && (b1->level > (first_level + 1)) &&
161 !(only_parens_till_b2 &&
162 (b1->target_col <= (b2->col + (1 + 2 * b1->level)))) &&
163 (b1->level > b2->level))
164 {
165 is_better = false;
166 }
167 }
168
169 if (is_better)
170 {
171 b1->first_level = first_level;
172 }
173 }
174
175 return is_better;
176 }
177
178 /**
179 * Calculate break priority.
180 *
181 * Example:
182 * e_code (`s_code' buffer, at the moment
183 * set_buf_break() is called)
184 * ptr (`s_code' buffer)
185 * corresponds_to (input buffer)
186 * Left most column col+1 (the column (31 here)).
187 * | |
188 * 1234567890123456789012345678901234567890
189 * if (!(mask[0] == '\\0'
190 * |
191 * target_col (assuming `lineup_to_parens' is true in this example)
192 * 1 2 3 2 | level == 2
193 * <--------------------->
194 * priority_code_length
195 */
196
set_priority(buf_break_st_ty * bb)197 static void set_priority (
198 buf_break_st_ty *bb)
199 {
200 bb->priority = bb->priority_code_length;
201
202 switch (bb->priority_code)
203 {
204 case bb_semicolon:
205 bb->priority += 6000;
206 break;
207 case bb_before_boolean_binary_op:
208 bb->priority += 5000;
209 break;
210 case bb_after_boolean_binary_op:
211 if (bb->priority_code_length > 2)
212 {
213 bb->priority += 5000;
214 }
215
216 if (settings.break_before_boolean_operator)
217 {
218 bb->priority -= 3;
219 }
220 break;
221 case bb_after_equal_sign:
222 bb->priority += 4000;
223 break;
224 case bb_attribute:
225 bb->priority += 3000;
226 break;
227 case bb_comma:
228 bb->priority += 2000;
229 break;
230 case bb_comparisation:
231 bb->priority += 1000;
232 break;
233 case bb_proc_call:
234 bb->priority -= 1000;
235 break;
236 case bb_operator6:
237 bb->priority += 600;
238 break;
239 case bb_operator5:
240 bb->priority += 500;
241 break;
242 case bb_operator4:
243 bb->priority += 400;
244 break;
245 case bb_operator2:
246 bb->priority += 200;
247 break;
248 case bb_doublecolon:
249 bb->priority += 100;
250 break;
251 default:
252 break;
253 }
254 }
255
256 /**
257 * This function is called at every position where we possibly want
258 * to break a line (if it gets too long).
259 */
260
set_buf_break(bb_code_ty code,int paren_targ)261 void set_buf_break (
262 bb_code_ty code,
263 int paren_targ)
264 {
265 int target_col, level;
266 int code_target = compute_code_target (paren_targ);
267 buf_break_st_ty *bb;
268
269 /* First, calculate the column that code following e_code would be
270 * printed in if we'd break the line here.
271 * This is done quite simular to compute_code_target(). */
272
273 /* Base indentation level (number of open left-braces) */
274
275 target_col = parser_state_tos->i_l_follow + 1;
276
277 /* Did we just parse a brace that will be put on the next line
278 * by this line break? */
279
280 if (*token == '{')
281 {
282 target_col -= settings.ind_size; /* Use `ind_size' because this only happens
283 * for the first brace of initializer blocks. */
284 }
285
286 /* Number of open brackets */
287
288 level = parser_state_tos->p_l_follow;
289
290 /* Did we just parse a bracket that will be put on the next line
291 * by this line break? */
292
293 if ((*token == '(') || (*token == '['))
294 {
295 --level; /* then don't take it into account */
296 }
297
298 /* Procedure name of function declaration? */
299
300 if (parser_state_tos->procname[0] &&
301 (token == parser_state_tos->procname))
302 {
303 target_col = 1;
304 }
305 else if (level == 0) /* No open brackets? */
306 {
307 if (parser_state_tos->in_stmt) /* Breaking a statement? */
308 {
309 target_col += settings.continuation_indent;
310 }
311 }
312 else if (!settings.lineup_to_parens)
313 {
314 target_col += settings.continuation_indent +
315 (settings.paren_indent * (level - 1));
316 }
317 else
318 {
319 if (parser_state_tos->paren_indents[level - 1] < 0)
320 {
321 target_col = -parser_state_tos->paren_indents[level - 1];
322 }
323 else
324 {
325 target_col = code_target + parser_state_tos->paren_indents[level - 1];
326 }
327 }
328
329 /* Store the position of `e_code' as the place to break this line. */
330
331 bb = xmalloc(sizeof(buf_break_st_ty));
332 bb->offset = e_code - s_code;
333 bb->level = level;
334 bb->target_col = target_col;
335 bb->corresponds_to = token;
336 *e_code = 0;
337 bb->col = count_columns (code_target, s_code, NULL_CHAR) - 1;
338
339 /* Calculate default priority. */
340
341 bb->priority_code_length = (e_code - s_code);
342 bb->priority_newline = (parser_state_tos->last_saw_nl &&
343 !parser_state_tos->broken_at_non_nl);
344
345 if (buf_break)
346 {
347 bb->first_level = buf_break->first_level;
348 }
349
350 switch (parser_state_tos->last_token)
351 {
352 case binary_op:
353 if ( ((e_code - s_code) >= 3) &&
354 (e_code[-3] == ' ') &&
355 (((e_code[-1] == '&') && (e_code[-2] == '&')) ||
356 ((e_code[-1] == '|') && (e_code[-2] == '|'))))
357 {
358 bb->priority_code = bb_after_boolean_binary_op;
359 }
360 else if ( (e_code - s_code >= 2) && (e_code[-1] == '=') &&
361 ( (e_code[-2] == ' ') ||
362 ( (e_code - s_code >= 3) &&
363 (e_code[-3] == ' ') &&
364 ( (e_code[-2] == '%') ||
365 (e_code[-2] == '^') ||
366 (e_code[-2] == '&') ||
367 (e_code[-2] == '*') ||
368 (e_code[-2] == '-') ||
369 (e_code[-2] == '+') ||
370 (e_code[-2] == '|')))))
371 {
372 bb->priority_code = bb_after_equal_sign;
373 }
374 else if ( ( ( (e_code - s_code) >= 2) &&
375 (e_code[-2] == ' ') &&
376 ( (e_code[-1] == '<') ||
377 (e_code[-1] == '>'))) ||
378 ( ( (e_code - s_code) >= 3) &&
379 (e_code[-3] == ' ') &&
380 (e_code[-1] == '=') &&
381 ( (e_code[-2] == '=') ||
382 (e_code[-2] == '!') ||
383 (e_code[-2] == '<') ||
384 (e_code[-2] == '>'))))
385 {
386 bb->priority_code = bb_comparisation;
387 }
388 else if ( (e_code[-1] == '+') ||
389 (e_code[-1] == '-'))
390 {
391 bb->priority_code = bb_operator6;
392 }
393 else if ( (e_code[-1] == '*') || (e_code[-1] == '/') || (e_code[-1] == '%'))
394 {
395 bb->priority_code = bb_operator5;
396 }
397 else
398 {
399 bb->priority_code = bb_binary_op;
400 }
401
402 break;
403 case comma:
404 bb->priority_code = bb_comma;
405 break;
406 default:
407 if ( (code == bb_binary_op) &&
408 ( (*token == '&') ||
409 (*token == '|')) &&
410 (*token == token[1]))
411 {
412 bb->priority_code = bb_before_boolean_binary_op;
413 }
414 else if (e_code[-1] == ';')
415 {
416 bb->priority_code = bb_semicolon;
417 }
418 else
419 {
420 bb->priority_code = code;
421 if (code == bb_struct_delim) /* . -> .* or ->* */
422 {
423 if (e_code[-1] == '*')
424 {
425 bb->priority_code = bb_operator4;
426 }
427 else
428 {
429 bb->priority_code = bb_operator2;
430 }
431 }
432 }
433 }
434 set_priority (bb);
435
436 /* Add buf_break to the list */
437
438 if (buf_break_list)
439 {
440 buf_break_list->next = bb;
441 }
442
443 bb->prev = buf_break_list;
444 bb->next = NULL;
445 buf_break_list = bb;
446
447 if (!buf_break || (bb->col <= settings.max_col))
448 {
449 if (better_break (bb, buf_break))
450 {
451 /* Found better buf_break. Get rid of all previous possible breaks. */
452
453 buf_break = bb;
454
455 for (bb = bb->prev; bb;)
456 {
457 buf_break_st_ty *obb = bb;
458
459 bb = bb->prev;
460 xfree(obb);
461 }
462
463 buf_break->prev = NULL;
464 }
465 }
466 }
467
468 /**
469 *
470 */
471
clear_buf_break_list(BOOLEAN * pbreak_line)472 void clear_buf_break_list (
473 BOOLEAN * pbreak_line)
474 {
475 buf_break_st_ty *bb;
476
477 for (bb = buf_break_list; bb;)
478 {
479 buf_break_st_ty *obb = bb;
480
481 bb = bb->prev;
482 xfree(obb);
483 }
484
485 buf_break = buf_break_list = NULL;
486 *pbreak_line = false;
487 }
488
489 /**
490 * @verbatim
491 * prev_code_target
492 * | prev_code_target + offset
493 * | |
494 * <----->if ((aaa == bbb) && xxx
495 * && xxx
496 * |
497 * new_code_target
498 * @endverbatim
499 */
500
set_next_buf_break(int prev_code_target,int new_code_target,int offset,BOOLEAN * pbreak_line)501 static void set_next_buf_break (
502 int prev_code_target,
503 int new_code_target,
504 int offset,
505 BOOLEAN * pbreak_line)
506 {
507 buf_break_st_ty *bb;
508
509 better_break (buf_break, NULL); /* Reset first_level */
510
511 if (buf_break_list == buf_break)
512 {
513 clear_buf_break_list (pbreak_line);
514 }
515 else
516 {
517 /* Correct all elements of the remaining buf breaks: */
518 for (bb = buf_break_list; bb; bb = bb->prev)
519 {
520 if (bb->target_col > buf_break->target_col && settings.lineup_to_parens)
521 {
522 bb->target_col -= ((prev_code_target + offset) - new_code_target);
523 }
524
525 bb->col -= ((prev_code_target + offset) - new_code_target);
526 bb->offset -= offset;
527 bb->priority_code_length -= offset;
528 bb->first_level = buf_break->first_level;
529
530 if (!buf_break->priority_newline)
531 {
532 bb->priority_newline = false;
533 }
534
535 set_priority (bb);
536
537 if (bb->prev == buf_break)
538 {
539 break;
540 }
541 }
542
543 xfree(buf_break);
544 if (!bb) goto ret;
545
546 /* Set buf_break to first break in the list */
547 buf_break = bb;
548
549 /* GDB_HOOK_buf_break */
550 buf_break->prev = NULL;
551
552 /* Find a better break of the existing breaks */
553 for (bb = buf_break; bb; bb = bb->next)
554 {
555 if (bb->col > settings.max_col)
556 {
557 continue;
558 }
559
560 if (better_break (bb, buf_break))
561 {
562 /* Found better buf_break. Get rid of all previous possible breaks. */
563 buf_break = bb;
564
565 for (bb = bb->prev; bb;)
566 {
567 buf_break_st_ty *obb = bb;
568
569 bb = bb->prev;
570 xfree(obb);
571 }
572 bb = buf_break;
573 buf_break->prev = NULL;
574 }
575 }
576 }
577
578 ret:
579 return;
580 }
581
582 /**
583 * Name: pad_output
584 * Description: Fill the output line with whitespace up to TARGET_COLUMN,
585 * given that the line is currently in column CURRENT_COLUMN.
586 *
587 * Returns: the ending column number.
588 *
589 * History:
590 */
pad_output(int cur_col,int target_column)591 static int pad_output(int cur_col, int target_column)
592 {
593 int offset = 0;
594 int align_target = target_column;
595 int tos = parser_state_tos->tos;
596
597 if (cur_col < target_column)
598 {
599 if (settings.use_tabs && (settings.tabsize > 1))
600 {
601 if (settings.align_with_spaces)
602 {
603 if (align_target >= parser_state_tos->ind_level)
604 align_target = parser_state_tos->ind_level;
605
606 /* If we're within an if/for/while, only use tabs
607 * to indent to the same level as the parent
608 * statement.
609 */
610 if (parser_state_tos->last_rw == rw_sp_paren &&
611 parser_state_tos->p_stack[tos] == stmt &&
612 *s_code && tos > 0)
613 {
614 do {
615 if (parser_state_tos->p_stack[tos] == ifstmt ||
616 parser_state_tos->p_stack[tos] == forstmt ||
617 parser_state_tos->p_stack[tos] == whilestmt)
618 break;
619 } while (--tos);
620 if (tos) align_target = parser_state_tos->il[tos];
621 } else if (parser_state_tos->p_stack[tos] == ifstmt ||
622 parser_state_tos->p_stack[tos] == forstmt ||
623 parser_state_tos->p_stack[tos] == whilestmt)
624 align_target = parser_state_tos->il[tos];
625
626 offset = (align_target - cur_col + 1) / settings.tabsize;
627 align_target = cur_col + (offset * settings.tabsize);
628 }
629
630 offset = settings.tabsize - (cur_col - 1) % settings.tabsize;
631 while (cur_col + offset <= align_target)
632 {
633 putc(TAB, output);
634 cur_col += offset;
635 offset = settings.tabsize;
636 }
637 }
638
639 while (cur_col < target_column)
640 {
641 putc(' ', output);
642 cur_col++;
643 }
644 }
645
646 return cur_col;
647 }
648
649 /**
650 * output the sequence of characters starting at begin and
651 * ending at the character _before_ end (the character at end is not output)
652 * to file.
653 */
654
output_substring(FILE * file,const char * begin,const char * end)655 static void output_substring(
656 FILE * file,
657 const char * begin,
658 const char * end)
659 {
660 const char * p;
661
662 for (p = begin; p < end; p++)
663 {
664 putc (*p, file);
665 }
666 }
667
668 /**
669 * Name: dump_line_label
670 * Description: routine that actually effects the printing of the new source's label section.
671 *
672 * Returns: current column number..
673 *
674 * History:
675 */
676
dump_line_label(void)677 static int dump_line_label(void)
678 {
679 int cur_col;
680
681 /* print lab, if any */
682
683 while ((e_lab > s_lab) && ((e_lab[-1] == ' ') ||
684 (e_lab[-1] == TAB)))
685 {
686 e_lab--;
687 }
688
689 cur_col = pad_output(1, compute_label_target());
690
691 /* force indentation of preprocessor directives.
692 * this happens when force_preproc_width > 0 */
693
694 if ((settings.force_preproc_width > 0) &&
695 (s_lab[0] == '#'))
696 {
697 int preproc_postcrement;
698 char *p = &s_lab[1];
699
700 while(*p == ' ')
701 {
702 p++;
703 }
704
705 preproc_postcrement = settings.force_preproc_width;
706
707 if (strncmp(p, "else", 4) == 0)
708 {
709 preproc_indent-=settings.force_preproc_width;
710 }
711 else if ((strncmp(p, "if", 2) == 0) ||
712 (strncmp(p, "ifdef", 5) == 0))
713 {
714 }
715 else if (strncmp(p, "elif", 4) == 0)
716 {
717 preproc_indent -= settings.force_preproc_width;
718 }
719 else if (strncmp(p, "endif", 5) == 0)
720 {
721 preproc_indent -= settings.force_preproc_width;
722 preproc_postcrement = 0;
723 }
724 else
725 {
726 preproc_postcrement = 0;
727 }
728
729 if (preproc_indent == 0)
730 {
731 fprintf (output, "#");
732 }
733 else
734 {
735 fprintf (output, "#%*s", preproc_indent, " ");
736 }
737
738 fprintf (output, "%.*s", (int) (e_lab - p), p);
739
740 cur_col = count_columns (cur_col + preproc_indent + 1, p, NULL_CHAR);
741 preproc_indent += preproc_postcrement;
742 }
743 else if ((s_lab[0] == '#') && ((strncmp (&s_lab[1], "else", 4) == 0) ||
744 (strncmp (&s_lab[1], "endif", 5) == 0)))
745 {
746 /* Treat #else and #endif as a special case because any text
747 * after #else or #endif should be converted to a comment. */
748
749 char *s = s_lab;
750
751 if (e_lab[-1] == EOL) /* Don't include EOL in the comment */
752 {
753 e_lab--;
754 }
755
756 do
757 {
758 putc (*s++, output);
759 ++cur_col;
760 } while ((s < e_lab) && ('a' <= *s) && (*s <= 'z'));
761
762 while (((*s == ' ') || (*s == TAB)) && (s < e_lab))
763 {
764 s++;
765 }
766
767 if (s < e_lab)
768 {
769 if (settings.tabsize > 1)
770 {
771 cur_col = pad_output (cur_col, cur_col + settings.tabsize -
772 (cur_col - 1) % settings.tabsize);
773 }
774 else
775 {
776 cur_col = pad_output (cur_col, cur_col + 2);
777 }
778
779 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
780 {
781 fprintf (output, "%.*s", (int)(e_lab - s), s);
782 }
783 else
784 {
785 fprintf (output, "/* %.*s */", (int)(e_lab - s), s);
786 }
787
788 /* no need to update cur_col: the very next thing will
789 be a new-line (or end of file) */
790 }
791 }
792 else
793 {
794 fprintf (output, "%.*s", (int) (e_lab - s_lab), s_lab);
795 cur_col = count_columns (cur_col, s_lab, NULL_CHAR);
796 }
797
798 return cur_col;
799 }
800
801 /**
802 *
803 */
804
count_parens(const char * string)805 static int count_parens(
806 const char * string)
807 {
808 int paren_level = 0;
809
810 while (*string)
811 {
812 switch (*string)
813 {
814 case '(':
815 case '[':
816 paren_level++;
817 break;
818 case ')':
819 case ']':
820 paren_level--;
821 break;
822 default:
823 break;
824 }
825
826 string++;
827 }
828
829 return paren_level;
830 }
831
832 /**
833 *
834 */
835
dump_line_code(int * pcur_col,int * pnot_truncated,int paren_targ,BOOLEAN * pbreak_line,int target_col_break)836 static void dump_line_code(
837 int * pcur_col,
838 int * pnot_truncated,
839 int paren_targ,
840 BOOLEAN * pbreak_line,
841 int target_col_break)
842 {
843 int paren_level = 0;
844
845 if (s_code != e_code)
846 { /* print code section, if any */
847 int i;
848 int target_col = 0;
849
850 /* If a comment begins this line, then indent it to the correct
851 * column for comments, otherwise the line starts with code,
852 * so indent it for code. */
853
854 if (embedded_comment_on_line == 1)
855 {
856 target_col = parser_state_tos->com_col;
857 }
858 else if (target_col_break != -1)
859 {
860 target_col = target_col_break;
861 }
862 else
863 {
864 target_col = compute_code_target (paren_targ);
865 }
866
867 /* If a line ends in an lparen character, the following line should
868 * not line up with the parenthesis, but should be indented by the
869 * usual amount. */
870
871 if (parser_state_tos->last_token == lparen)
872 {
873 parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1] +=
874 settings.ind_size - 1;
875 }
876
877 *pcur_col = pad_output (*pcur_col, target_col);
878
879 if (*pbreak_line && (s_com == e_com) &&
880 (buf_break->target_col <= buf_break->col))
881 {
882 int offset;
883 int len;
884 char c;
885 char *ptr = &s_code[buf_break->offset];
886
887 if (*ptr != ' ')
888 {
889 --ptr;
890 }
891
892 /* Add target_col (and negate) the brackets that are
893 * actually printed. The remaining brackets must
894 * be given an offset of . */
895
896 offset = ptr - s_code + 1;
897
898 for (i = 0; i < parser_state_tos->p_l_follow; i++)
899 {
900 if (parser_state_tos->paren_indents[i] >= 0)
901 {
902 if (parser_state_tos->paren_indents[i] < ptr - s_code)
903 {
904 parser_state_tos->paren_indents[i] =
905 -(parser_state_tos->paren_indents[i] + target_col);
906 }
907 else
908 {
909 parser_state_tos->paren_indents[i] -= offset;
910 }
911 }
912 }
913
914 for (i = parser_state_tos->p_l_follow;
915 i < parser_state_tos->paren_indents_size; ++i)
916 {
917 if (parser_state_tos->paren_indents[i] >= (ptr - s_code))
918 {
919 parser_state_tos->paren_indents[i] -= offset;
920 }
921 }
922
923 output_substring(output, s_code, s_code + buf_break->offset);
924
925 c = s_code[buf_break->offset];
926
927 s_code[buf_break->offset] = '\0';
928
929 *pcur_col = count_columns (*pcur_col, s_code, NULL_CHAR);
930
931 paren_level += count_parens(s_code);
932
933 s_code[buf_break->offset] = c;
934
935 *pnot_truncated = 0;
936
937 len = (e_code - ptr - 1);
938 memmove (s_code, ptr + 1, len);
939
940 e_code = s_code + len;
941 #if COLOR_DEBUG
942 fputs (" \e[31m", output);
943
944 output_substring(output, s_code, e_code);
945
946 fputs (" \e[0m", output);
947 #endif
948 *e_code = '\0';
949 s_code_corresponds_to = buf_break->corresponds_to;
950 prev_target_col_break = buf_break->target_col;
951
952 if (!buf_break->priority_newline)
953 {
954 parser_state_tos->broken_at_non_nl = true;
955 }
956
957 set_next_buf_break (target_col, buf_break->target_col,
958 offset, pbreak_line);
959
960 buf_break_used = 1;
961
962 *pbreak_line = (buf_break != NULL) &&
963 (output_line_length() > settings.max_col);
964 }
965 else
966 {
967 for (i = 0; i < parser_state_tos->p_l_follow; i++)
968 {
969 if (parser_state_tos->paren_indents[i] >= 0)
970 {
971 parser_state_tos->paren_indents[i] =
972 -(parser_state_tos->paren_indents[i] +
973 target_col);
974 }
975 }
976
977 output_substring(output, s_code, e_code);
978
979 *pcur_col = count_columns (*pcur_col, s_code, NULL_CHAR);
980 clear_buf_break_list (pbreak_line);
981 }
982 }
983 }
984
985 /**
986 * Name: dump_line
987 * Description: routine that actually effects the printing of the new source.
988 * It prints the label section, followed by the code section with
989 * the appropriate nesting level, followed by any comments.
990 *
991 * Returns: None.
992 *
993 * History:
994 */
995
dump_line(int force_nl,int * paren_targ,BOOLEAN * pbreak_line)996 extern void dump_line (
997 int force_nl,
998 int * paren_targ,
999 BOOLEAN * pbreak_line)
1000 {
1001 int cur_col;
1002 int not_truncated = 1;
1003 int target_col_break = -1;
1004
1005 if (buf_break_used)
1006 {
1007 buf_break_used = 0;
1008 target_col_break = prev_target_col_break;
1009 }
1010 else if (force_nl)
1011 {
1012 parser_state_tos->broken_at_non_nl = false;
1013 }
1014
1015
1016 if (parser_state_tos->procname[0] && !parser_state_tos->classname[0] &&
1017 (s_code_corresponds_to == parser_state_tos->procname))
1018 {
1019 parser_state_tos->procname = "\0";
1020 }
1021 else if (parser_state_tos->procname[0] && parser_state_tos->classname[0] &&
1022 (s_code_corresponds_to == parser_state_tos->classname))
1023 {
1024 parser_state_tos->procname = "\0";
1025 parser_state_tos->classname = "\0";
1026 }
1027
1028 /* A blank line */
1029
1030 if ((s_code == e_code) && (s_lab == e_lab) && (s_com == e_com))
1031 {
1032 /* If we have a formfeed on a blank line, we should just output it,
1033 * rather than treat it as a normal blank line. */
1034
1035 if (parser_state_tos->use_ff)
1036 {
1037 putc ('\014', output);
1038 parser_state_tos->use_ff = false;
1039 }
1040 else
1041 {
1042 n_real_blanklines++;
1043 }
1044 }
1045 else
1046 {
1047 if (prefix_blankline_requested && (n_real_blanklines == 0))
1048 {
1049 if ((prefix_blankline_requested_code != decl) ||
1050 !parser_state_tos->decl_on_line)
1051 {
1052 n_real_blanklines = 1;
1053 }
1054 }
1055 else if (settings.swallow_optional_blanklines && (n_real_blanklines > 1))
1056 {
1057 n_real_blanklines = 1;
1058 }
1059
1060 while (--n_real_blanklines >= 0)
1061 {
1062 putc (EOL, output);
1063 }
1064
1065 n_real_blanklines = 0;
1066
1067 if ((e_lab != s_lab) || (e_code != s_code))
1068 {
1069 ++code_lines; /* keep count of lines with code */
1070 }
1071
1072 if (e_lab != s_lab)
1073 {
1074 cur_col = dump_line_label();
1075 }
1076 else
1077 {
1078 cur_col = 1; /* there is no label section */
1079 }
1080
1081 parser_state_tos->pcase = false;
1082
1083 /* Remove trailing spaces */
1084 while ((*(e_code - 1) == ' ') && (e_code > s_code))
1085 {
1086 *(--e_code) = NULL_CHAR;
1087 }
1088
1089 dump_line_code(&cur_col, ¬_truncated, *paren_targ, pbreak_line,
1090 target_col_break);
1091
1092 if (s_com != e_com)
1093 {
1094 {
1095 /* Here for comment printing. */
1096 int target = parser_state_tos->com_col;
1097 char *com_st = s_com;
1098
1099 if (cur_col > target)
1100 {
1101 putc (EOL, output);
1102 cur_col = 1;
1103 ++out_lines;
1104 }
1105
1106 cur_col = pad_output (cur_col, target);
1107 fwrite (com_st, e_com - com_st, 1, output);
1108 cur_col += e_com - com_st;
1109 com_lines++;
1110 }
1111 }
1112 else if (embedded_comment_on_line)
1113 {
1114 com_lines++;
1115 }
1116
1117 embedded_comment_on_line = 0;
1118
1119 if (parser_state_tos->use_ff)
1120 {
1121 putc ('\014', output);
1122 parser_state_tos->use_ff = false;
1123 }
1124 else
1125 {
1126 putc (EOL, output);
1127 }
1128
1129 ++out_lines;
1130
1131 if ((parser_state_tos->just_saw_decl == 1) &&
1132 settings.blanklines_after_declarations)
1133 {
1134 prefix_blankline_requested = 1;
1135 prefix_blankline_requested_code = decl;
1136 parser_state_tos->just_saw_decl = 0;
1137 }
1138 else
1139 {
1140 prefix_blankline_requested = postfix_blankline_requested;
1141 prefix_blankline_requested_code = postfix_blankline_requested_code;
1142 }
1143 postfix_blankline_requested = 0;
1144
1145 }
1146
1147 /* if we are in the middle of a declaration, remember that fact
1148 * for proper comment indentation */
1149
1150 parser_state_tos->decl_on_line = parser_state_tos->in_decl;
1151
1152 /* next line should be indented if we have not completed this stmt */
1153
1154 parser_state_tos->ind_stmt = parser_state_tos->in_stmt;
1155
1156 e_lab = s_lab;
1157 *s_lab = '\0'; /* reset buffers */
1158
1159 if (not_truncated)
1160 {
1161 e_code = s_code;
1162 *s_code = '\0';
1163 s_code_corresponds_to = NULL;
1164 }
1165
1166 e_com = s_com;
1167
1168 *s_com = '\0';
1169
1170 parser_state_tos->ind_level = parser_state_tos->i_l_follow;
1171 parser_state_tos->paren_level = parser_state_tos->p_l_follow;
1172
1173 if (parser_state_tos->paren_level > 0)
1174 {
1175 /* If we broke the line and the following line will
1176 * begin with a rparen, the indentation is set for
1177 * the column of the rparen *before* the break - reset
1178 * the column to the position after the break. */
1179
1180 if (!not_truncated && ((*s_code == '(') || (*s_code == '[')) &&
1181 (parser_state_tos->paren_level >= 2))
1182 {
1183 *paren_targ = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 2];
1184 }
1185 else
1186 {
1187 *paren_targ = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1];
1188 }
1189 }
1190 else
1191 {
1192 *paren_targ = 0;
1193 }
1194
1195 if (inhibited)
1196 {
1197 char *p = cur_line;
1198
1199 while (--n_real_blanklines >= 0)
1200 {
1201 putc (EOL, output);
1202 }
1203
1204 n_real_blanklines = 0;
1205
1206 do
1207 {
1208 while ((*p != '\0') && (*p != EOL))
1209 {
1210 putc (*p++, output);
1211 }
1212
1213 if ((*p == '\0') &&
1214 ((unsigned long) (p - current_input->data) == current_input->size))
1215 {
1216 in_prog_pos = p;
1217 buf_end = p;
1218 buf_ptr = p;
1219 had_eof = true;
1220 return;
1221 }
1222
1223 if (*p == EOL)
1224 {
1225 cur_line = p + 1;
1226 line_no++;
1227 }
1228
1229 putc (*p++, output);
1230 while ((*p == ' ') || (*p == TAB))
1231 {
1232 putc (*p, output);
1233 p++;
1234 }
1235
1236 if ((*p == '/') && ((*(p + 1) == '*') ||
1237 (*(p + 1) == '/')))
1238 {
1239 /* We've hit a comment. See if turns formatting
1240 back on. */
1241 putc (*p++, output);
1242 putc (*p++, output);
1243
1244 while ((*p == ' ') || (*p == TAB))
1245 {
1246 putc (*p, output);
1247 p++;
1248 }
1249
1250 if (!strncmp (p, "*INDENT-ON*", 11))
1251 {
1252 do
1253 {
1254 while ((*p != '\0') && (*p != EOL))
1255 {
1256 putc (*p++, output);
1257 }
1258
1259 if ((*p == '\0') &&
1260 (((unsigned long) (p - current_input->data) ==
1261 current_input->size)))
1262 {
1263 in_prog_pos = p;
1264 buf_end = p;
1265 buf_ptr = p;
1266 had_eof = true;
1267 return;
1268 }
1269 else
1270 {
1271 if (*p == EOL)
1272 {
1273 inhibited = false;
1274 cur_line = p + 1;
1275 line_no++;
1276 }
1277
1278 putc (*p++, output);
1279 }
1280 } while (inhibited);
1281 }
1282 }
1283 } while (inhibited);
1284
1285 in_prog_pos = cur_line;
1286 buf_end = cur_line;
1287 buf_ptr = cur_line;
1288
1289 fill_buffer ();
1290 }
1291
1292 /* Output the rest already if we really wanted a new-line after this code. */
1293 if (buf_break_used && (s_code != e_code) && force_nl)
1294 {
1295 prefix_blankline_requested = 0;
1296 dump_line (true, paren_targ, pbreak_line);
1297 }
1298
1299 return;
1300 }
1301
1302 /**
1303 * Name: flush_output
1304 * Description: Flushes any buffered output to the output file.
1305 *
1306 * Returns: None
1307 *
1308 * History:
1309 */
1310
flush_output(void)1311 extern void flush_output(void)
1312 {
1313 fflush (output);
1314 }
1315
1316 /**
1317 * Name: open_output
1318 * Description: Opens the output file in read/write mode.
1319 *
1320 * Returns: None
1321 *
1322 * History:
1323 */
1324
open_output(const char * filename,const char * mode)1325 void open_output(
1326 const char * filename,
1327 const char * mode)
1328 {
1329 if (filename == NULL)
1330 {
1331 output = stdout;
1332 }
1333 else
1334 {
1335 output = fopen(filename, mode); /* open the file for read + write
1336 * (but see the trunc function) */
1337 if (output == NULL)
1338 {
1339 fatal(_("indent: can't create %s\n"), filename);
1340 }
1341 }
1342 }
1343
1344 /**
1345 * Name: reopen_output_trunc
1346 * Description: Reopens the output file truncated.
1347 *
1348 * Returns: None
1349 *
1350 * History:
1351 */
1352
reopen_output_trunc(const char * filename)1353 extern void reopen_output_trunc(
1354 const char * filename)
1355 {
1356 output = freopen(filename, "w", output);
1357
1358 }
1359
1360 /**
1361 * Name: close_output
1362 * Description: Closes the output file.
1363 *
1364 * Returns: None
1365 *
1366 * History:
1367 */
1368
close_output(struct stat * file_stats,const char * filename)1369 extern void close_output(
1370 struct stat * file_stats,
1371 const char * filename)
1372 {
1373 if (output != stdout)
1374 {
1375 if (fclose(output) != 0)
1376 {
1377 fatal(_("Can't close output file %s"), filename);
1378 }
1379 else
1380 {
1381 #ifdef PRESERVE_MTIME
1382 if (file_stats != NULL && filename)
1383 {
1384 struct utimbuf buf;
1385
1386 buf.actime = time (NULL);
1387 buf.modtime = file_stats->st_mtime;
1388 if (utime(filename, &buf) != 0)
1389 {
1390 WARNING(_("Can't preserve modification time on output file %s"),
1391 filename, 0);
1392 }
1393 }
1394 #endif
1395 }
1396 }
1397 }
1398
1399 /**
1400 *
1401 */
1402
inhibit_indenting(BOOLEAN flag)1403 extern void inhibit_indenting(
1404 BOOLEAN flag)
1405 {
1406 inhibited = flag;
1407 }
1408
1409 /**
1410 * Return the column in which we should place the code in s_code.
1411 */
1412
compute_code_target(int paren_targ)1413 int compute_code_target (
1414 int paren_targ)
1415 {
1416 int target_col;
1417
1418 if (buf_break_used)
1419 {
1420 return prev_target_col_break;
1421 }
1422
1423 if (parser_state_tos->procname[0] &&
1424 (s_code_corresponds_to == parser_state_tos->procname))
1425 {
1426 target_col = 1;
1427
1428 if (!parser_state_tos->paren_level)
1429 {
1430 return target_col;
1431 }
1432 }
1433 else
1434 {
1435 target_col = parser_state_tos->ind_level + 1;
1436 }
1437
1438 if (!parser_state_tos->paren_level)
1439 {
1440 if (parser_state_tos->ind_stmt)
1441 {
1442 target_col += settings.continuation_indent;
1443 }
1444
1445 return target_col;
1446 }
1447
1448 if (!settings.lineup_to_parens)
1449 {
1450 return target_col + settings.continuation_indent +
1451 (settings.paren_indent * (parser_state_tos->paren_level - 1));
1452 }
1453
1454 return paren_targ;
1455 }
1456
1457 /**
1458 *
1459 */
1460
count_columns(int column,char * bp,int stop_char)1461 int count_columns (
1462 int column,
1463 char *bp,
1464 int stop_char)
1465 {
1466 while (*bp != stop_char && *bp != NULL_CHAR)
1467 {
1468 switch (*bp++)
1469 {
1470 case EOL:
1471 case '\f': /* form feed */
1472 column = 1;
1473 break;
1474 case TAB:
1475 column += settings.tabsize - (column - 1) % settings.tabsize;
1476 break;
1477 case 010: /* backspace */
1478 --column;
1479 break;
1480 #ifdef COLOR_DEBUG
1481 case '\e': /* ANSI color */
1482 while (*bp++ != 'm')
1483 {
1484 }
1485
1486 break;
1487 #endif
1488 default:
1489 ++column;
1490 break;
1491 }
1492 }
1493
1494 return column;
1495 }
1496
1497 /**
1498 *
1499 */
1500
compute_label_target(void)1501 int compute_label_target (void)
1502 {
1503 /* maybe there should be some option to tell indent where to put public:,
1504 * private: etc. ? */
1505
1506 if (*s_lab == '#')
1507 {
1508 return 1;
1509 }
1510
1511 if (parser_state_tos->pcase)
1512 {
1513 return parser_state_tos->cstk[parser_state_tos->tos] + 1;
1514 }
1515
1516 if (settings.c_plus_plus && parser_state_tos->in_decl)
1517 {
1518 /* FIXME: does this belong here at all? */
1519 return 1;
1520 }
1521 else if (settings.label_offset < 0)
1522 {
1523 return parser_state_tos->ind_level + settings.label_offset + 1;
1524 }
1525 else
1526 {
1527 return settings.label_offset + 1;
1528 }
1529 }
1530
1531 /**
1532 * Compute the length of the line we will be outputting.
1533 */
1534
output_line_length(void)1535 int output_line_length (void)
1536 {
1537 int code_length = 0;
1538 int com_length = 0;
1539 int length;
1540
1541 if (s_lab == e_lab)
1542 {
1543 length = 0;
1544 }
1545 else
1546 {
1547 length = count_columns (compute_label_target (), s_lab, EOL) - 1;
1548 }
1549
1550 if (s_code != e_code)
1551 {
1552 int code_col = compute_code_target(paren_target);
1553
1554 code_length = count_columns(code_col, s_code, EOL) - code_col;
1555 }
1556
1557 if (s_com != e_com)
1558 {
1559 int com_col = parser_state_tos->com_col;
1560
1561 com_length = count_columns(com_col, s_com, EOL) - com_col;
1562 }
1563
1564 if (code_length != 0)
1565 {
1566 length += compute_code_target(paren_target) - 1 + code_length;
1567
1568 if (embedded_comment_on_line)
1569 {
1570 length += com_length;
1571 }
1572 }
1573
1574 return length;
1575 }
1576
1577