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 }