001    /*
002     * Copyright (C) 2010 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.util;
021    
022    import org.crsh.shell.io.ShellWriter;
023    import org.crsh.shell.io.ShellWriterContext;
024    
025    import java.io.IOException;
026    
027    /**
028     * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
029     * @version $Revision$
030     */
031    public class LineFeedWriter implements ShellWriter {
032    
033      /** . */
034      private static final int NOT_PADDED = 0;
035    
036      /** . */
037      private static final int PADDING = 1;
038    
039      /** . */
040      private static final int PADDED = 2;
041    
042      /** . */
043      private final Appendable out;
044    
045      /** . */
046      private final String lineFeed;
047    
048      /** . */
049      private int status;
050    
051      public LineFeedWriter(Appendable out) {
052        this(out, "\r\n");
053      }
054    
055      public LineFeedWriter(Appendable out, String lineFeed) {
056        this.out = out;
057        this.lineFeed = lineFeed;
058        this.status = NOT_PADDED;
059      }
060    
061      public Appendable append(char c) throws IOException {
062        return append(null, c);
063      }
064    
065      public ShellWriter append(ShellWriterContext ctx, final char c) throws IOException {
066        return append(ctx, Character.toString(c));
067      }
068    
069      public Appendable append(CharSequence csq, int start, int end) throws IOException {
070        return append(null, csq, start, end);
071      }
072    
073      public Appendable append(CharSequence csq) throws IOException {
074        return append(null, csq);
075      }
076    
077      public ShellWriter append(ShellWriterContext ctx, CharSequence csq) throws IOException {
078        return append(ctx, csq, 0, csq.length());
079      }
080    
081      public ShellWriter append(ShellWriterContext ctx, CharSequence csq, int start, int end) throws IOException {
082        int previous = start;
083        int to = start + end;
084        for (int i = start;i < to;i++) {
085          char c = csq.charAt(i);
086          if (c == '\r') {
087            if (i > previous) {
088              realAppend(ctx, csq, previous, i);
089            }
090            previous = i + 1;
091          } else if (c == '\n') {
092            if (i > previous) {
093              realAppend(ctx, csq, previous, i);
094            }
095            writeLF(ctx);
096            previous = i + 1;
097            i++;
098          }
099        }
100        if (to != previous) {
101          realAppend(ctx, csq, previous, to);
102        }
103        return this;
104      }
105    
106      private void realAppend(ShellWriterContext ctx, CharSequence csq, int off, int end) throws IOException {
107        if (end > off) {
108    
109          //
110          switch (status) {
111            case NOT_PADDED:
112              if (ctx != null) {
113                status = PADDING;
114                ctx.pad(this);
115              }
116              status = PADDED;
117              break;
118            case PADDING:
119            case PADDED:
120              // Do nothing
121              break;
122            default:
123              throw new AssertionError();
124          }
125    
126          //
127          out.append(csq, off, end);
128    
129          //
130          switch (status) {
131            case PADDING:
132              // Do nothing
133              break;
134            case PADDED:
135              if (ctx != null) {
136                ctx.text(csq, off, end);
137              }
138              break;
139            default:
140              throw new AssertionError();
141          }
142        }
143      }
144    
145      private void writeLF(ShellWriterContext ctx) throws IOException {
146        switch (status) {
147          case PADDING:
148            throw new IllegalStateException();
149          case PADDED:
150            status = NOT_PADDED;
151          case NOT_PADDED:
152            out.append(lineFeed);
153            if (ctx != null) {
154              ctx.lineFeed();
155            }
156            break;
157          default:
158            throw new AssertionError();
159        }
160      }
161    }