Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dx.util;
     18 
     19 import java.io.FilterWriter;
     20 import java.io.IOException;
     21 import java.io.Writer;
     22 
     23 /**
     24  * Writer that wraps another writer and passes width-limited and
     25  * optionally-prefixed output to its subordinate. When lines are
     26  * wrapped they are automatically indented based on the start of the
     27  * line.
     28  */
     29 public final class IndentingWriter extends FilterWriter {
     30     /** {@code null-ok;} optional prefix for every line */
     31     private final String prefix;
     32 
     33     /** {@code > 0;} the maximum output width */
     34     private final int width;
     35 
     36     /** {@code > 0;} the maximum indent */
     37     private final int maxIndent;
     38 
     39     /** {@code >= 0;} current output column (zero-based) */
     40     private int column;
     41 
     42     /** whether indent spaces are currently being collected */
     43     private boolean collectingIndent;
     44 
     45     /** {@code >= 0;} current indent amount */
     46     private int indent;
     47 
     48     /**
     49      * Constructs an instance.
     50      *
     51      * @param out {@code non-null;} writer to send final output to
     52      * @param width {@code >= 0;} the maximum output width (not including
     53      * {@code prefix}), or {@code 0} for no maximum
     54      * @param prefix {@code non-null;} the prefix for each line
     55      */
     56     public IndentingWriter(Writer out, int width, String prefix) {
     57         super(out);
     58 
     59         if (out == null) {
     60             throw new NullPointerException("out == null");
     61         }
     62 
     63         if (width < 0) {
     64             throw new IllegalArgumentException("width < 0");
     65         }
     66 
     67         if (prefix == null) {
     68             throw new NullPointerException("prefix == null");
     69         }
     70 
     71         this.width = (width != 0) ? width : Integer.MAX_VALUE;
     72         this.maxIndent = width >> 1;
     73         this.prefix = (prefix.length() == 0) ? null : prefix;
     74 
     75         bol();
     76     }
     77 
     78     /**
     79      * Constructs a no-prefix instance.
     80      *
     81      * @param out {@code non-null;} writer to send final output to
     82      * @param width {@code >= 0;} the maximum output width (not including
     83      * {@code prefix}), or {@code 0} for no maximum
     84      */
     85     public IndentingWriter(Writer out, int width) {
     86         this(out, width, "");
     87     }
     88 
     89     /** {@inheritDoc} */
     90     @Override
     91     public void write(int c) throws IOException {
     92         synchronized (lock) {
     93             if (collectingIndent) {
     94                 if (c == ' ') {
     95                     indent++;
     96                     if (indent >= maxIndent) {
     97                         indent = maxIndent;
     98                         collectingIndent = false;
     99                     }
    100                 } else {
    101                     collectingIndent = false;
    102                 }
    103             }
    104 
    105             if ((column == width) && (c != '\n')) {
    106                 out.write('\n');
    107                 column = 0;
    108                 /*
    109                  * Note: No else, so this should fall through to the next
    110                  * if statement.
    111                  */
    112             }
    113 
    114             if (column == 0) {
    115                 if (prefix != null) {
    116                     out.write(prefix);
    117                 }
    118 
    119                 if (!collectingIndent) {
    120                     for (int i = 0; i < indent; i++) {
    121                         out.write(' ');
    122                     }
    123                     column = indent;
    124                 }
    125             }
    126 
    127             out.write(c);
    128 
    129             if (c == '\n') {
    130                 bol();
    131             } else {
    132                 column++;
    133             }
    134         }
    135     }
    136 
    137     /** {@inheritDoc} */
    138     @Override
    139     public void write(char[] cbuf, int off, int len) throws IOException {
    140         synchronized (lock) {
    141             while (len > 0) {
    142                 write(cbuf[off]);
    143                 off++;
    144                 len--;
    145             }
    146         }
    147     }
    148 
    149     /** {@inheritDoc} */
    150     @Override
    151     public void write(String str, int off, int len) throws IOException {
    152         synchronized (lock) {
    153             while (len > 0) {
    154                 write(str.charAt(off));
    155                 off++;
    156                 len--;
    157             }
    158         }
    159     }
    160 
    161     /**
    162      * Indicates that output is at the beginning of a line.
    163      */
    164     private void bol() {
    165         column = 0;
    166         collectingIndent = (maxIndent != 0);
    167         indent = 0;
    168     }
    169 }
    170