001 /* 002 * Copyright (C) 2012 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 package org.crsh.cli.impl.line; 020 021 /** 022 * Line parser. 023 * 024 * @author Julien Viet 025 */ 026 public final class LineParser { 027 028 public static abstract class Visitor { 029 public void onChar(int index, Quoting quoting, boolean backslash, char c) { } 030 public void openStrongQuote(int index) {} 031 public void closeStrongQuote(int index) {} 032 public void openWeakQuote(int index) {} 033 public void closeWeakQuote(int index) {} 034 public void reset() {} 035 } 036 037 /** . */ 038 private static final int NORMAL = 0, WEAK_QUOTING = 1, STRONG_QUOTING = 2; 039 040 /** . */ 041 private int status = NORMAL; 042 043 /** . */ 044 private boolean escaped = false; 045 046 /** . */ 047 private int index = 0; 048 049 /** . */ 050 private final Visitor[] visitors; 051 052 public LineParser(Visitor... visitors) { 053 this.visitors = visitors; 054 } 055 056 public boolean crlf() { 057 if (escaped) { 058 escaped = false; 059 return false; 060 } else { 061 switch (status) { 062 case WEAK_QUOTING: 063 for (Visitor visitor : visitors) visitor.onChar(index, Quoting.WEAK, false, '\n'); 064 index++; 065 return false; 066 case STRONG_QUOTING: 067 for (Visitor visitor : visitors) visitor.onChar(index, Quoting.STRONG, false, '\n'); 068 index++; 069 return false; 070 default: 071 return true; 072 } 073 } 074 } 075 076 public LineParser append(CharSequence s) { 077 int len = s.length(); 078 for (int index = 0;index < len;index++) { 079 append(s.charAt(index)); 080 } 081 return this; 082 } 083 084 public LineParser append(char c) { 085 if (!escaped) { 086 switch (status) { 087 case NORMAL: 088 switch (c) { 089 case '\\': 090 escaped = true; 091 break; 092 case '\"': 093 for (Visitor visitor : visitors) visitor.openWeakQuote(index); 094 status = WEAK_QUOTING; 095 index++; 096 break; 097 case '\'': 098 for (Visitor visitor : visitors) visitor.openStrongQuote(index); 099 index++; 100 status = STRONG_QUOTING; 101 break; 102 default: 103 for (Visitor visitor : visitors) visitor.onChar(index, null, false, c); 104 index++; 105 break; 106 } 107 break; 108 case WEAK_QUOTING: 109 switch (c) { 110 case '"': 111 for (Visitor visitor : visitors) visitor.closeWeakQuote(index); 112 index++; 113 status = NORMAL; 114 break; 115 case '\\': 116 escaped = true; 117 break; 118 default: 119 for (Visitor visitor : visitors) visitor.onChar(index, Quoting.WEAK, false, c); 120 index++; 121 break; 122 } 123 break; 124 case STRONG_QUOTING: 125 switch (c) { 126 case '\'': 127 for (Visitor visitor : visitors) visitor.closeStrongQuote(index); 128 index++; 129 status = NORMAL; 130 break; 131 case '\\': 132 escaped = true; 133 break; 134 default: 135 for (Visitor visitor : visitors) visitor.onChar(index, Quoting.STRONG, false, c); 136 index++; 137 break; 138 } 139 break; 140 } 141 } else { 142 switch (status) { 143 case NORMAL: 144 for (Visitor visitor : visitors) visitor.onChar(index + 1, null, true, c); 145 index += 2; 146 break; 147 case WEAK_QUOTING: 148 for (Visitor visitor : visitors) visitor.onChar(index + 1, Quoting.WEAK, true, c); 149 index += 2; 150 break; 151 case STRONG_QUOTING: 152 if (c == '\'') { 153 // Special case 154 status = NORMAL; 155 for (Visitor visitor : visitors) visitor.onChar(index, Quoting.STRONG, false, '\\'); 156 for (Visitor visitor : visitors) visitor.closeStrongQuote(index + 1); 157 index += 2; 158 } else { 159 for (Visitor visitor : visitors) visitor.onChar(index + 1, Quoting.STRONG, true, c); 160 index += 2; 161 } 162 break; 163 } 164 escaped = false; 165 } 166 return this; 167 } 168 169 public void reset() { 170 index = 0; 171 status = NORMAL; 172 escaped = false; 173 for (Visitor visitor : visitors) visitor.reset(); 174 } 175 }