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, &not_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