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.shell.io;
021
022 import org.crsh.text.CharReader;
023 import org.crsh.text.ShellAppendable;
024 import org.crsh.text.Style;
025
026 import java.io.IOException;
027
028 /**
029 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
030 * @version $Revision$
031 */
032 public class ShellWriter implements ShellAppendable {
033
034 /** . */
035 private static final int NOT_PADDED = 0;
036
037 /** . */
038 private static final int PADDING = 1;
039
040 /** . */
041 private static final int PADDED = 2;
042
043 /** . */
044 private final CharReader reader;
045
046 /** . */
047 private final String lineFeed;
048
049 /** . */
050 private int status;
051
052 public ShellWriter(CharReader reader) {
053 this(reader, "\r\n");
054 }
055
056 public ShellWriter(CharReader reader, String lineFeed) {
057 this.reader = reader;
058 this.lineFeed = lineFeed;
059 this.status = NOT_PADDED;
060 }
061
062 public Appendable append(char c) throws IOException {
063 return append(null, c);
064 }
065
066 public ShellWriter append(ShellWriterContext ctx, final char c) throws IOException {
067 return append(ctx, Character.toString(c));
068 }
069
070 public ShellWriter append(final Style d) {
071 reader.append(d);
072 return this;
073 }
074
075 public Appendable append(CharSequence csq, int start, int end) throws IOException {
076 return append(null, csq, start, end);
077 }
078
079 public Appendable append(CharSequence csq) throws IOException {
080 return append(null, csq);
081 }
082
083 public ShellWriter append(ShellWriterContext ctx, CharSequence csq) throws IOException {
084 return append(ctx, csq, 0, csq.length());
085 }
086
087 public ShellWriter append(ShellWriterContext ctx, CharSequence csq, int start, int end) throws IOException {
088 int previous = start;
089 int to = start + end;
090 for (int i = start;i < to;i++) {
091 char c = csq.charAt(i);
092 if (c == '\r') {
093 if (i > previous) {
094 realAppend(ctx, csq, previous, i);
095 }
096 previous = i + 1;
097 } else if (c == '\n') {
098 if (i > previous) {
099 realAppend(ctx, csq, previous, i);
100 }
101 writeLF(ctx);
102 previous = i + 1;
103 i++;
104 }
105 }
106 if (to != previous) {
107 realAppend(ctx, csq, previous, to);
108 }
109 return this;
110 }
111
112 private void realAppend(ShellWriterContext ctx, CharSequence csq, int off, int end) throws IOException {
113 if (end > off) {
114
115 //
116 switch (status) {
117 case NOT_PADDED:
118 if (ctx != null) {
119 status = PADDING;
120 ctx.pad(this);
121 }
122 status = PADDED;
123 break;
124 case PADDING:
125 case PADDED:
126 // Do nothing
127 break;
128 default:
129 throw new AssertionError();
130 }
131
132 //
133 reader.append(csq.subSequence(off, end).toString());
134
135 //
136 switch (status) {
137 case PADDING:
138 // Do nothing
139 break;
140 case PADDED:
141 if (ctx != null) {
142 ctx.text(csq, off, end);
143 }
144 break;
145 default:
146 throw new AssertionError();
147 }
148 }
149 }
150
151 private void writeLF(ShellWriterContext ctx) throws IOException {
152 switch (status) {
153 case PADDING:
154 throw new IllegalStateException();
155 case PADDED:
156 status = NOT_PADDED;
157 case NOT_PADDED:
158 reader.append(lineFeed);
159 if (ctx != null) {
160 ctx.lineFeed();
161 }
162 break;
163 default:
164 throw new AssertionError();
165 }
166 }
167
168 public boolean isEmpty() {
169 return reader.isEmpty();
170 }
171 }