Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/indent/output.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * Copyright (c) 2002 D.Ingamells
 *
 * File:    output.c
 * Purpose: Interface to the output file for the indent tool.
 *
 * History:
 * 2002-03-04 D.Ingamells Creation.
 * 2002-11-10 Cristalle Azundris Sabon <[email protected]>
 *            Added --preprocessor-indentation (ppi)   if set, will indent nested
 *            preprocessor-statements with n spaces per level.  overrides -lps.
 */

#include <stdio.h>
#include <sys/types.h>
#include <utime.h>
#include <sys/stat.h>

#include "indent.h"
#include "sys.h"
#include "globs.h"
#include "output.h"

RCSTAG_CC ("$Id: output.c,v 1.5 2002/12/12 17:36:49 david Exp $");

static FILE            * output       = NULL;
static BOOLEAN           inhibited    = 0;
static buf_break_st_ty * buf_break_list = NULL;

/* Priority mask bits */
static const int boolean_operator = 1;

buf_break_st_ty * buf_break = NULL;

int             out_lines      = 0;     /* used in output.c indent.c */
int             com_lines      = 0;     /* used in output.c indent.c comments.c */

int           prev_target_col_break = 0;
int           buf_break_used        = 0;
int           preproc_indent        = 0;

/*
 * Returns `true' when `b1' is a better place to break the code than `b2'.
 * `b1' must be newer.
 *
 * When `lineup_to_parens' is true, do not break more then 1 level deeper
 * unless that doesn't cost us "too much" indentation.
 * What is "too much" is determined in a fuzzy way as follows:
 * Consider the example,
 *   while (!(!(!(!(!(!(mask
 *                      || (((a_very_long_expression_that_cant_be_broken
 * here we prefer to break after `mask' instead of after `while'.
 * This is because the `target_col' is pretty close to the break point
 * of the `while': "mask"->target_col - "while"->col == 15 == "mask"->level * 2 + 1.
 */

static int better_break (
    buf_break_st_ty *b1,
    const buf_break_st_ty *b2)
{
    static int first_level;
    int is_better;

    if (!b2)
    {
        first_level = b1->level;
        b1->first_level = first_level;
        return 1;
    }
    if (b2->target_col >= b2->col + 1)
    {
        is_better = true;
    }
    else if (settings.honour_newlines && b2->priority_newline)
    {
        is_better = false;
    }
    else if (settings.honour_newlines && b1->priority_newline)
    {
        is_better = true;
    }
    else
    {
        int only_parens_till_b2 = 0;

        is_better = (b1->priority > b2->priority);
        
        if (is_better)
        {
            char *p;

            for (p = &s_code[b2->offset]; p >= s_code; --p)
            {
                if (*p == '!')
                {
                    --p;
                }
                
                if (*p != '(')
                {
                    break;
                }
            }
            if (p < s_code)
            {
                only_parens_till_b2 = 1;
            }
        }
        if (settings.lineup_to_parens && (b1->level > first_level + 1) &&
            !(only_parens_till_b2 && (b1->target_col <= b2->col + (1 + 2 * b1->level))) &&
            (b1->level > b2->level))
        {
            is_better = false;
        }
        
    }
    if (is_better)
    {
        b1->first_level = first_level;
    }
    
    return is_better;
}

/*
 * Example:
 *                              e_code          (`s_code' buffer, at the moment set_buf_break() is called)
 *                              ptr             (`s_code' buffer)
 *                              corresponds_to  (input buffer)
 * Left most column             col+1           (the column (31 here)).
 * |                             |
 * 1234567890123456789012345678901234567890
 *         if (!(mask[0] == '\\0' 
 *               |
 *             target_col (assuming `lineup_to_parens' is true in this example)
 *            1 2    3 2         | level == 2
 *         <--------------------->
 *          priority_code_length
 */

/*
 * Calculate break priority.
 */
static void set_priority (
              buf_break_st_ty *bb)
{
    bb->priority = bb->priority_code_length;

    switch (bb->priority_code)
    {
        case bb_semicolon:
            bb->priority += 6000;
            break;
        case bb_before_boolean_binary_op:
            bb->priority += 5000;
            break;
        case bb_after_boolean_binary_op:
            if (bb->priority_code_length > 2)
            {
                bb->priority += 5000;
            }
            if (settings.break_before_boolean_operator)
            {
                bb->priority -= 3;
            }
            break;
        case bb_after_equal_sign:
            bb->priority += 4000;
            break;
        case bb_attribute:
            bb->priority += 3000;
            break;
        case bb_comma:
            bb->priority += 2000;
            break;
        case bb_comparisation:
            bb->priority += 1000;
            break;
        case bb_proc_call:
            bb->priority -= 1000;
            break;
        case bb_operator6:
            bb->priority += 600;
            break;
        case bb_operator5:
            bb->priority += 500;
            break;
        case bb_operator4:
            bb->priority += 400;
            break;
        case bb_operator2:
            bb->priority += 200;
            break;
        case bb_doublecolon:
            bb->priority += 100;
            break;
        default:
            break;
    }
}
/*
 * This function is called at every position where we possibly want
 * to break a line (if it gets too long).
 */

void set_buf_break (
    bb_code_ty code,
    int        paren_targ)
{
    int target_col, level;
    int code_target = compute_code_target (paren_targ);
    buf_break_st_ty *bb;

    /* First, calculate the column that code following e_code would be
     * printed in if we'd break the line here.
     * This is done quite simular to compute_code_target(). */

    /* Base indentation level (number of open left-braces) */
  
    target_col = parser_state_tos->i_l_follow + 1;
  
    /* Did we just parse a brace that will be put on the next line
     * by this line break? */
  
    if (*token == '{')
    {
        target_col -= settings.ind_size; /* Use `ind_size' because this only happens
                                          * for the first brace of initializer blocks. */
    }

    /* Number of open brackets */

    level = parser_state_tos->p_l_follow;
  
    /* Did we just parse a bracket that will be put on the next line
     * by this line break? */
  
    if (*token == '(' || *token == '[')
    {
        --level;                        /* then don't take it into account */
    }

    /* Procedure name of function declaration? */

    if (parser_state_tos->procname[0] && token == parser_state_tos->procname)
    {
        target_col = 1;
    }
    else if (level == 0)                /* No open brackets? */
    {
        if (parser_state_tos->in_stmt)  /* Breaking a statement? */
        {
            target_col += settings.continuation_indent;
        }
    }
    else if (!settings.lineup_to_parens)
    {
        target_col += settings.continuation_indent + (settings.paren_indent * (level - 1));
    }
    else
    {
        if (parser_state_tos->paren_indents[level - 1] < 0)
        {
            target_col = -parser_state_tos->paren_indents[level - 1];
        }
        else
        {
            target_col = code_target + parser_state_tos->paren_indents[level - 1];
        }
    }

    /* Store the position of `e_code' as the place to break this line. */

    bb = (buf_break_st_ty *) xmalloc (sizeof (buf_break_st_ty));
    bb->offset = e_code - s_code;
    bb->level = level;
    bb->target_col = target_col;
    bb->corresponds_to = token;
    *e_code = 0;
    bb->col = count_columns (code_target, s_code, NULL_CHAR) - 1;

    /* Calculate default priority. */
    
    bb->priority_code_length = (e_code - s_code);
    bb->priority_newline = (parser_state_tos->last_saw_nl && !parser_state_tos->broken_at_non_nl);

    if (buf_break)
    {
        bb->first_level = buf_break->first_level;
    }
    
    switch (parser_state_tos->last_token)
    {
        case binary_op:
            if ((e_code - s_code) >= 3 && e_code[-3] == ' '
                && ((e_code[-1] == '&' && e_code[-2] == '&') ||
                    (e_code[-1] == '|' && e_code[-2] == '|')))
            {
                bb->priority_code = bb_after_boolean_binary_op;
            }
            else if ( (e_code - s_code >= 2) && (e_code[-1] == '=') &&
                      ( (e_code[-2] == ' ') ||
                        ( (e_code - s_code >= 3) &&
                          (e_code[-3] == ' ') &&
                          ( (e_code[-2] == '%') ||
                            (e_code[-2] == '^') ||
                            (e_code[-2] == '&') ||
                            (e_code[-2] == '*') ||
                            (e_code[-2] == '-') ||
                            (e_code[-2] == '+') ||
                            (e_code[-2] == '|')))))
            {
                bb->priority_code = bb_after_equal_sign;
            }
            else if ( ( ( (e_code - s_code) >= 2) &&
                        (e_code[-2] == ' ') &&
                        ( (e_code[-1] == '<') ||
                          (e_code[-1] == '>'))) ||
                      ( ( (e_code - s_code) >= 3) &&
                        (e_code[-3] == ' ') &&
                        (e_code[-1] == '=')  &&
                        ( (e_code[-2] == '=') ||
                          (e_code[-2] == '!') ||
                          (e_code[-2] == '<') ||
                          (e_code[-2] == '>'))))
            {
                bb->priority_code = bb_comparisation;
            }
            else if ( (e_code[-1] == '+') ||
                      (e_code[-1] == '-'))
            {
                bb->priority_code = bb_operator6;
            }
            else if ( (e_code[-1] == '*') || (e_code[-1] == '/') || (e_code[-1] == '%'))
            {
                bb->priority_code = bb_operator5;
            }
            else
            {
                bb->priority_code = bb_binary_op;
            }
            
            break;
        case comma:
            bb->priority_code = bb_comma;
            break;
        default:
            if ( (code == bb_binary_op) &&
                 ( (*token == '&') ||
                   (*token == '|')) &&
                 (*token == token[1]))
            {
                bb->priority_code = bb_before_boolean_binary_op;
            }
            else if (e_code[-1] == ';')
            {
                bb->priority_code = bb_semicolon;
            }
            else
            {
                bb->priority_code = code;
                if (code == bb_struct_delim)    /* . -> .* or ->* */
                {
                    if (e_code[-1] == '*')
                    {
                        bb->priority_code = bb_operator4;
                    }
                    else
                    {
                        bb->priority_code = bb_operator2;
                    }
                }
            }
    }
    set_priority (bb);

    /* Add buf_break to the list */
    
    if (buf_break_list)
    {
        buf_break_list->next = bb;
    }
    
    bb->prev = buf_break_list;
    bb->next = NULL;
    buf_break_list = bb;

    if (buf_break && bb->col > settings.max_col)
    {
        return;
    }

    if (!better_break (bb, buf_break))
    {
        return;
    }

    /* Found better buf_break.  Get rid of all previous possible breaks. */

    buf_break = bb;
    
    for (bb = bb->prev; bb;)
    {
        buf_break_st_ty *obb = bb;

        bb = bb->prev;
        free (obb);
    }
    
    buf_break->prev = NULL;
}

void clear_buf_break_list (void)
{
    buf_break_st_ty *bb;

    for (bb = buf_break_list; bb;)
    {
        buf_break_st_ty *obb = bb;

        bb = bb->prev;
        free (obb);
    }
    
    buf_break = buf_break_list = NULL;
    break_line = 0;
}

/*
 *        prev_code_target
 *        |                prev_code_target + offset
 *        |                |
 * <----->if ((aaa == bbb) && xxx
 *            && xxx
 *            |
 *            new_code_target
 */
static void set_next_buf_break (
                    int prev_code_target,
                    int new_code_target,
                    int offset)
{
    buf_break_st_ty *bb;

    better_break (buf_break, NULL);     /* Reset first_level */

    if (buf_break_list == buf_break)
    {
        clear_buf_break_list ();
        return;
    }

    /* Correct all elements of the remaining buf breaks: */
    for (bb = buf_break_list; bb; bb = bb->prev)
    {
        if (bb->target_col > buf_break->target_col && settings.lineup_to_parens)
        {
            bb->target_col -= ((prev_code_target + offset) - new_code_target);
        }
        
        bb->col -= ((prev_code_target + offset) - new_code_target);
        bb->offset -= offset;
        bb->priority_code_length -= offset;
        bb->first_level = buf_break->first_level;
        
        if (!buf_break->priority_newline)
        {
            bb->priority_newline = false;
        }
        
        set_priority (bb);
        
        if (bb->prev == buf_break)
        {
            break;
        }
    }

    free (buf_break);

    /* Set buf_break to first break in the list */
    
    buf_break = bb;
    
    /* GDB_HOOK_buf_break */
    
    buf_break->prev = NULL;

    /* Find a better break of the existing breaks */
    
    for (bb = buf_break; bb; bb = bb->next)
    {
        if (bb->col > settings.max_col)
        {
            continue;
        }
        
        if (better_break (bb, buf_break))
        {
            /* Found better buf_break.  Get rid of all previous possible breaks. */
            buf_break = bb;
            
            for (bb = bb->prev; bb;)
            {
                buf_break_st_ty *obb = bb;

                bb = bb->prev;
                free (obb);
            }
            bb = buf_break;
            buf_break->prev = NULL;
        }
    }
}

/*
 * Name:         pad_output
 * Description:  Fill the output line with whitespace up to TARGET_COLUMN,
 *               given that the line is currently in column CURRENT_COLUMN.
 *
 * Returns:      the ending column number.
 *
 * History:
 */

static int pad_output (
    int current_column,
    int target_column)
{
    if (current_column >= target_column)
    {
        return current_column;
    }
    
    if (settings.use_tabs && settings.tabsize > 1)
    {
        int offset = settings.tabsize - (current_column - 1) % settings.tabsize;
      
        while (current_column + offset <= target_column)
        {
            putc (TAB, output);
            current_column += offset;
            offset = settings.tabsize;
        }
    }

    while (current_column < target_column)
    {
        putc (' ', output);
        current_column++;
    }

    return current_column;
}

/*
 * Name:         dump_line
 * Description:  routine that actually effects the printing of the new source.
 *               It prints the label section, followed by the code section with
 *               the appropriate nesting level, followed by any comments.
 *
 * Returns:      None.
 *
 * History:
 */

extern void dump_line (
    int force_nl,
    int *paren_targ)
{
    int cur_col;
    int target_col = 0;
    int not_truncated = 1;
    int target_col_break = -1;

    if (buf_break_used)
    {
        buf_break_used = 0;
        target_col_break = prev_target_col_break;
    }
    else if (force_nl)
    {
        parser_state_tos->broken_at_non_nl = false;
    }
    

    if (parser_state_tos->procname[0] && !parser_state_tos->classname[0] &&
        (s_code_corresponds_to == parser_state_tos->procname))
    {
        parser_state_tos->procname = "\0";
    }
    else if (parser_state_tos->procname[0] && parser_state_tos->classname[0] &&
             (s_code_corresponds_to == parser_state_tos->classname))
    {
        parser_state_tos->procname = "\0";
        parser_state_tos->classname = "\0";
    }

    /* A blank line */
    
    if ((s_code == e_code) && (s_lab == e_lab) && (s_com == e_com))
    {
        /* If we have a formfeed on a blank line, we should just output it,
         * rather than treat it as a normal blank line.  */
        
        if (parser_state_tos->use_ff)
        {
            putc ('\014', output);
            parser_state_tos->use_ff = false;
        }
        else
        {
            n_real_blanklines++;
        }
    }
    else
    {
        if (prefix_blankline_requested && n_real_blanklines == 0)
        {
            n_real_blanklines = 1;
        }
        else if (settings.swallow_optional_blanklines && (n_real_blanklines > 1))
        {
            n_real_blanklines = 1;
        }

        while (--n_real_blanklines >= 0)
        {
            putc (EOL, output);
        }
        
        n_real_blanklines = 0;

        if (e_lab != s_lab || e_code != s_code)
        {
            ++code_lines;               /* keep count of lines with code */
        }

        if (e_lab != s_lab)
        {
            /* print lab, if any */
            while ((e_lab > s_lab) && ((e_lab[-1] == ' ') || 
                                       (e_lab[-1] == TAB)))
            {
                e_lab--;
            }
            
            cur_col = pad_output (1, compute_label_target ());
            
            /* force indentation of preprocessor directives.
             * this happens when force_preproc_width > 0 */
            
            if ((settings.force_preproc_width > 0) &&
                (s_lab[0] == '#'))
            {
                int preproc_postcrement;
                char *p = &s_lab[1];

                while(*p == ' ')
                {
                    p++;
                }

                preproc_postcrement = settings.force_preproc_width;

                if (strncmp(p, "else", 4) == 0)
                {
                    preproc_indent-=settings.force_preproc_width;
                }
                else if((strncmp(p, "if", 2) == 0) ||
                        (strncmp(p, "ifdef", 5) == 0))
                {
                }
                else if (strncmp(p, "elif", 4) == 0)
                {
                    preproc_indent -= settings.force_preproc_width;
                }
                else if(strncmp(p, "endif", 5) == 0)
                {
                    preproc_indent -= settings.force_preproc_width;
                    preproc_postcrement = 0;
                }
                else
                {
                    preproc_postcrement = 0;
                }

                if (preproc_indent == 0)
                {
                    fprintf (output, "#");
                }
                else
                {
                    fprintf (output, "#%*s", preproc_indent, " ");
                }
                
                fprintf (output, "%.*s", (int) (e_lab - p), p);

                cur_col = count_columns (cur_col + preproc_indent + 1, p, NULL_CHAR);
                preproc_indent += preproc_postcrement;
            }
            else if ((s_lab[0] == '#') && ((strncmp (&s_lab[1], "else", 4) == 0) ||
                                           (strncmp (&s_lab[1], "endif", 5) == 0)))
            {
                /* Treat #else and #endif as a special case because any text
                 * after #else or #endif should be converted to a comment.  */
                
                char *s = s_lab;

                if (e_lab[-1] == EOL)   /* Don't include EOL in the comment */
                {
                    e_lab--;
                }
                
                do
                {
                    putc (*s++, output);
                    ++cur_col;
                } while ((s < e_lab) && ('a' <= *s) && (*s <= 'z'));
                
                while (((*s == ' ') || (*s == TAB)) && (s < e_lab))
                {
                    s++;
                }
                
                if (s < e_lab)
                {
                    if (settings.tabsize > 1)
                    {
                        cur_col = pad_output (cur_col, cur_col + settings.tabsize -
                                              (cur_col - 1) % settings.tabsize);
                    }
                    else
                    {
                        cur_col = pad_output (cur_col, cur_col + 2);
                    }
                    
                    if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
                    {
                        fprintf (output, "%.*s", e_lab - s, s);
                    }
                    else
                    {
                        fprintf (output, "/* %.*s */", e_lab - s, s);
                    }
                    
                    /* no need to update cur_col: the very next thing will
                       be a new-line (or end of file) */
                }
            }
            else
            {
                fprintf (output, "%.*s", (int) (e_lab - s_lab), s_lab);
                cur_col = count_columns (cur_col, s_lab, NULL_CHAR);
            }
        }
        else
        {
            cur_col = 1;                /* there is no label section */
        }

        parser_state_tos->pcase = false;

        /* Remove trailing spaces */
        while ((*(e_code - 1) == ' ') && (e_code > s_code))
        {
            *(--e_code) = NULL_CHAR;
        }
        
        if (s_code != e_code)
        {                       /* print code section, if any */
            char *p;
            int i;

            /* If a comment begins this line, then indent it to the right
             * column for comments, otherwise the line starts with code,
             * so indent it for code. */
            
            if (embedded_comment_on_line == 1)
            {
                target_col = parser_state_tos->com_col;
            }
            else if (target_col_break != -1)
            {
                target_col = target_col_break;
            }
            else
            {
                target_col = compute_code_target (*paren_targ);
            }

            /* If a line ends in an lparen character, the following line should
             * not line up with the parenthesis, but should be indented by the
             * usual amount.  */
            
            if (parser_state_tos->last_token == lparen)
            {
                parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1] += settings.ind_size - 1;
            }

            cur_col = pad_output (cur_col, target_col);

            if (break_line && (s_com == e_com) &&
                (buf_break->target_col <= buf_break->col))
            {
                int offset, len;
                char c;
                char *ptr = &s_code[buf_break->offset];

                if (*ptr != ' ')
                {
                    --ptr;
                }

                /* Add target_col (and negate) the brackets that are
                 * actually printed.  The remaining brackets must
                 * be given an offset of . */
                
                offset = ptr - s_code + 1;

                for (i = 0; i < parser_state_tos->p_l_follow; i++)
                {
                    if (parser_state_tos->paren_indents[i] >= 0)
                    {
                        if (parser_state_tos->paren_indents[i] < ptr - s_code)
                        {
                            parser_state_tos->paren_indents[i] =
                                    -(parser_state_tos->paren_indents[i] + target_col);
                        }
                        else
                        {
                            parser_state_tos->paren_indents[i] -= offset;
                        }
                    }
                }
                
                for (i = parser_state_tos->p_l_follow; 
                     i < parser_state_tos->paren_indents_size; ++i)
                {
                    if (parser_state_tos->paren_indents[i] >= (ptr - s_code))
                    {
                        parser_state_tos->paren_indents[i] -= offset;
                    }
                }

                for (p = s_code; p < s_code + buf_break->offset; p++)
                {
                    putc (*p, output);
                }

                c = s_code[buf_break->offset];
                s_code[buf_break->offset] = '\0';
                cur_col = count_columns (cur_col, s_code, NULL_CHAR);
                s_code[buf_break->offset] = c;

                not_truncated = 0;
                len = (e_code - ptr - 1);
                memmove (s_code, ptr + 1, len);
                e_code = s_code + len;
#if COLOR_DEBUG
                fputs (" \e[31m", output);
                for (p = s_code; p < e_code; p++)
                {
                    putc (*p, output);
                }
                
                fputs (" \e[0m", output);
#endif
                *e_code = '\0';
                s_code_corresponds_to = buf_break->corresponds_to;
                prev_target_col_break = buf_break->target_col;
                
                if (!buf_break->priority_newline)
                {
                    parser_state_tos->broken_at_non_nl = true;
                }
                
                set_next_buf_break (target_col, buf_break->target_col, offset);
                buf_break_used = 1;
                break_line = (buf_break != NULL) && (output_line_length () > settings.max_col);
            }
            else
            {
                for (i = 0; i < parser_state_tos->p_l_follow; i++)
                {
                    if (parser_state_tos->paren_indents[i] >= 0)
                    {
                        parser_state_tos->paren_indents[i] = -(parser_state_tos->paren_indents[i] + target_col);
                    }
                }

                for (p = s_code; p < e_code; p++)
                {
                    putc (*p, output);
                }
                
                cur_col = count_columns (cur_col, s_code, NULL_CHAR);
                clear_buf_break_list ();
            }
        }

        if (s_com != e_com)
        {
            {
                /* Here for comment printing. */
                int target = parser_state_tos->com_col;
                char *com_st = s_com;

                if (cur_col > target)
                {
                    putc (EOL, output);
                    cur_col = 1;
                    ++out_lines;
                }

                cur_col = pad_output (cur_col, target);
                fwrite (com_st, e_com - com_st, 1, output);
                cur_col += e_com - com_st;
                com_lines++;
            }
        }
        else if (embedded_comment_on_line)
        {
            com_lines++;
        }
        
        embedded_comment_on_line = 0;

        if (parser_state_tos->use_ff)
        {
            putc ('\014', output);
            parser_state_tos->use_ff = false;
        }
        else
        {
            putc (EOL, output);
        }

        ++out_lines;
        
        if ((parser_state_tos->just_saw_decl == 1) && 
            settings.blanklines_after_declarations)
        {
            prefix_blankline_requested = 1;
            prefix_blankline_requested_code = decl;
            parser_state_tos->just_saw_decl = 0;
        }
        else
        {
            prefix_blankline_requested = postfix_blankline_requested;
            prefix_blankline_requested_code = postfix_blankline_requested_code;
        }
        postfix_blankline_requested = 0;
        
    }

    /* if we are in the middle of a declaration, remember that fact
     * for proper comment indentation */
    
    parser_state_tos->decl_on_line = parser_state_tos->in_decl;

    /* next line should be indented if we have not completed this stmt */
    
    parser_state_tos->ind_stmt = parser_state_tos->in_stmt;

    e_lab = s_lab;
    *s_lab = '\0';    /* reset buffers */
    
    if (not_truncated)
    {
        e_code = s_code;
        *s_code = '\0';
        s_code_corresponds_to = NULL;
    }

    e_com = s_com;
    
    *s_com = '\0';

    parser_state_tos->ind_level = parser_state_tos->i_l_follow;
    parser_state_tos->paren_level = parser_state_tos->p_l_follow;
    
    if (parser_state_tos->paren_level > 0)
    {
        /* If we broke the line and the following line will
         * begin with a rparen, the indentation is set for
         * the column of the rparen *before* the break - reset
         * the column to the position after the break. */

        if (!not_truncated && ((*s_code == '(') || (*s_code == '[')) && 
            (parser_state_tos->paren_level >= 2))
        {
            *paren_targ = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 2];
        }
        else
        {
            *paren_targ = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1];
        }
    }
    else
    {
        *paren_targ = 0;
    }

    if (inhibited)
    {
        char *p = cur_line;

        while (--n_real_blanklines >= 0)
        {
            putc (EOL, output);
        }
        
        n_real_blanklines = 0;

        do
        {
            while ((*p != '\0') && (*p != EOL))
            {
                putc (*p++, output);
            }
            
            if ((*p == '\0') && 
                ((unsigned long) (p - current_input->data) == current_input->size))
            {
                in_prog_pos = p;
                buf_end = p;
                buf_ptr = p;
                had_eof = true;
                return;
            }

            if (*p == EOL)
            {
                cur_line = p + 1;
                line_no++;
            }
            
            putc (*p++, output);
            while ((*p == ' ') || (*p == TAB))
            {
                putc (*p, output);
                p++;
            }
            
            if ((*p == '/') && ((*(p + 1) == '*') ||
                                (*(p + 1) == '/')))
            {
                /* We've hit a comment.  See if turns formatting
                   back on. */
                putc (*p++, output);
                putc (*p++, output);
                
                while ((*p == ' ') || (*p == TAB))
                {
                    putc (*p, output);
                    p++;
                }
                
                if (!strncmp (p, "*INDENT-ON*", 11))
                {
                    do
                    {
                        while ((*p != '\0') && (*p != EOL))
                        {
                            putc (*p++, output);
                        }
                        
                        if ((*p == '\0') &&
                            (((unsigned long) (p - current_input->data) == current_input->size)))
                        {
                            in_prog_pos = p;
                            buf_end     = p;
                            buf_ptr     = p;
                            had_eof     = true;
                            return;
                        }
                        else
                        {
                            if (*p == EOL)
                            {
                                inhibited = false;
                                cur_line = p + 1;
                                line_no++;
                            }
                            
                            putc (*p++, output);
                        }
                    } while (inhibited);
                }
            }
        } while (inhibited);

        in_prog_pos = cur_line;
        buf_end     = cur_line;
        buf_ptr     = cur_line;

        fill_buffer ();
    }

    /* Output the rest already if we really wanted a new-line after this code. */
    if (buf_break_used && (s_code != e_code) && force_nl)
    {
        prefix_blankline_requested = 0;
        dump_line (true, paren_targ);
    }

    return;
}

/*
 * Name:         flush_output
 * Description:  Flushes any buffered output to the output file.
 *
 * Returns:      None
 *
 * History:
 */

extern void flush_output(void)
{
    fflush (output);
}

/*
 * Name:         open_output
 * Description:  Opens the output file in read/write mode.
 *
 * Returns:      None
 *
 * History:
 */

void open_output(
    const char * filename,
    const char * mode)
{
    if (filename == NULL)
    {
        output = stdout;
    }
    else
    {
        output = fopen(filename, mode);  /* open the file for read + write
                                          *  (but see the trunc function) */
        if (output == NULL)
        {
            fprintf (stderr, _("indent: can't create %s\n"), filename);
            exit (indent_fatal);
        }
    }
}

/*
 * Name:         reopen_output_trunc
 * Description:  Reopens the output file truncated.
 *
 * Returns:      None
 *
 * History:
 */

extern void reopen_output_trunc(
    const char * filename)
{
    output = freopen(filename, "w", output);

}

/*
 * Name:         close_output
 * Description:  Closes the output file.
 *
 * Returns:      None
 *
 * History:
 */

extern void close_output(
     struct stat * file_stats,
     const char  * filename)
{
    if (output != stdout)
    {
        if (fclose(output) != 0)
        {
            fatal(_("Can't close output file %s"), filename);
        }
        else
        {
#ifdef PRESERVE_MTIME
            if (file_stats != NULL)
            {
                struct utimbuf buf;
                
                buf.actime = time (NULL);
                buf.modtime = file_stats->st_mtime;
                if (utime(filename, &buf) != 0)
                {
                    WARNING(_("Can't preserve modification time on output file %s"),
                            filename, 0);
                }
            }
#endif
        }
    }
}

extern inhibit_indenting(
    BOOLEAN flag)
{
    inhibited = flag;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].