001: /*
002: * This is free software, licensed under the Gnu Public License (GPL)
003: * get a copy from <http://www.gnu.org/licenses/gpl.html>
004: * $Id: SetCommand.java,v 1.24 2005/11/27 16:20:28 hzeller Exp $
005: * author: Henner Zeller <H.Zeller@acm.org>
006: */
007: package henplus.commands;
008:
009: import henplus.AbstractCommand;
010: import henplus.CommandDispatcher;
011: import henplus.HenPlus;
012: import henplus.SQLSession;
013: import henplus.event.ExecutionListener;
014: import henplus.io.ConfigurationContainer;
015: import henplus.view.Column;
016: import henplus.view.ColumnMetaData;
017: import henplus.view.TableRenderer;
018: import henplus.view.util.SortedMatchIterator;
019:
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.Map;
024: import java.util.Set;
025: import java.util.SortedMap;
026: import java.util.StringTokenizer;
027: import java.util.TreeMap;
028:
029: /**
030: * document me.
031: */
032: public final class SetCommand extends AbstractCommand {
033: private final static String SETTINGS_FILENAME = "settings";
034: private final static String SPECIAL_LAST_COMMAND = "_HENPLUS_LAST_COMMAND";
035: private final static ColumnMetaData[] SET_META;
036:
037: static {
038: SET_META = new ColumnMetaData[2];
039: SET_META[0] = new ColumnMetaData("Name");
040: SET_META[1] = new ColumnMetaData("Value");
041: }
042:
043: private final Set _specialVariables;
044: private final SortedMap _variables;
045: private final HenPlus _henplus;
046: private final ConfigurationContainer _config;
047:
048: /**
049: * returns the command-strings this command can handle.
050: */
051: public String[] getCommandList() {
052: return new String[] { "set-var", "unset-var" };
053: }
054:
055: public SetCommand(HenPlus henplus) {
056: _henplus = henplus;
057: _variables = new TreeMap();
058: _specialVariables = new HashSet();
059: _config = _henplus
060: .createConfigurationContainer(SETTINGS_FILENAME);
061: _variables.putAll(_config.readProperties());
062: }
063:
064: public void registerLastCommandListener(CommandDispatcher dispatcher) {
065: _specialVariables.add(SPECIAL_LAST_COMMAND);
066: dispatcher.addExecutionListener(new ExecutionListener() {
067: public void beforeExecution(SQLSession session,
068: String command) {
069: }
070:
071: public void afterExecution(SQLSession session,
072: String command, int result) {
073: setVariable(SPECIAL_LAST_COMMAND, command.trim());
074: }
075: });
076: }
077:
078: public boolean requiresValidSession(String cmd) {
079: return false;
080: }
081:
082: public Map getVariableMap() {
083: return _variables;
084: }
085:
086: /**
087: * execute the command given.
088: */
089: public int execute(SQLSession currentSession, String cmd,
090: String param) {
091: StringTokenizer st = new StringTokenizer(param);
092: int argc = st.countTokens();
093:
094: if ("set-var".equals(cmd)) {
095: /*
096: * no args. only show.
097: */
098: if (argc == 0) {
099: SET_META[0].resetWidth();
100: SET_META[1].resetWidth();
101: TableRenderer table = new TableRenderer(SET_META,
102: HenPlus.out());
103: Iterator vars = _variables.entrySet().iterator();
104: while (vars.hasNext()) {
105: Map.Entry entry = (Map.Entry) vars.next();
106: Column[] row = new Column[4];
107: row[0] = new Column((String) entry.getKey());
108: row[1] = new Column((String) entry.getValue());
109: //row[2] = new Column("");
110: //row[3] = new Column("X");
111: table.addRow(row);
112: }
113: table.closeTable();
114: return SUCCESS;
115: }
116: /*
117: * more than one arg
118: */
119: else if (argc >= 2) {
120: String varname = (String) st.nextElement();
121: int pos = 0;
122: int paramLength = param.length();
123: // skip whitespace after 'set'
124: while (pos < paramLength
125: && Character.isWhitespace(param.charAt(pos))) {
126: ++pos;
127: }
128: // skip non-whitespace after 'set ': variable name
129: while (pos < paramLength
130: && !Character.isWhitespace(param.charAt(pos))) {
131: ++pos;
132: }
133: // skip whitespace before vlue..
134: while (pos < paramLength
135: && Character.isWhitespace(param.charAt(pos))) {
136: ++pos;
137: }
138: String value = param.substring(pos);
139: if (value.startsWith("\"") && value.endsWith("\"")) {
140: value = value.substring(1, value.length() - 1);
141: } else if (value.startsWith("\'")
142: && value.endsWith("\'")) {
143: value = value.substring(1, value.length() - 1);
144: }
145: setVariable(varname, value);
146: return SUCCESS;
147: }
148: return SYNTAX_ERROR;
149: } else if ("unset-var".equals(cmd)) {
150: if (argc >= 1) {
151: while (st.hasMoreElements()) {
152: String varname = (String) st.nextElement();
153: if (!_variables.containsKey(varname)) {
154: HenPlus.msg().println(
155: "unknown variable '" + varname + "'");
156: } else {
157: _variables.remove(varname);
158: }
159: }
160: return SUCCESS;
161: }
162: return SYNTAX_ERROR;
163: }
164: return SUCCESS;
165: }
166:
167: private void setVariable(String name, String value) {
168: _variables.put(name, value);
169: }
170:
171: /**
172: * used, if the command dispatcher notices the attempt to expand
173: * a variable. This is a partial variable name, that starts with '$'
174: * or '${'.
175: */
176: public Iterator completeUserVar(String variable) {
177: if (!variable.startsWith("$")) {
178: return null; // strange, shouldn't happen.
179: }
180: final boolean hasBrace = variable.startsWith("${");
181: final String prefix = (hasBrace ? "${" : "$");
182: final String postfix = (hasBrace ? "}" : "");
183: final String name = variable.substring(prefix.length());
184: //HenPlus.msg().println("VAR: " + variable);
185: //HenPlus.msg().println("NAME: " + name);
186: SortedMatchIterator it = new SortedMatchIterator(name,
187: _variables);
188: it.setPrefix(prefix);
189: it.setSuffix(postfix);
190: return it;
191: }
192:
193: /**
194: * complete variable names.
195: */
196: public Iterator complete(CommandDispatcher disp,
197: String partialCommand, final String lastWord) {
198: StringTokenizer st = new StringTokenizer(partialCommand);
199: String cmd = (String) st.nextElement();
200: int argc = st.countTokens();
201: final HashSet alreadyGiven = new HashSet();
202: if ("set-var".equals(cmd)) {
203: if (argc > ("".equals(lastWord) ? 0 : 1)) {
204: return null;
205: }
206: } else { // 'unset'
207: /*
208: * remember all variables, that have already been given on
209: * the commandline and exclude from completion..
210: */
211: while (st.hasMoreElements()) {
212: alreadyGiven.add(st.nextElement());
213: }
214: }
215: return new SortedMatchIterator(lastWord, _variables) {
216: protected boolean exclude(String current) {
217: return alreadyGiven.contains(current);
218: }
219: };
220: }
221:
222: public void shutdown() {
223: Map writeMap = new HashMap();
224: writeMap.putAll(_variables);
225: Iterator toRemove = _specialVariables.iterator();
226: while (toRemove.hasNext()) {
227: String varname = (String) toRemove.next();
228: writeMap.remove(varname);
229: }
230:
231: _config.storeProperties(writeMap, true, "user variables");
232: }
233:
234: /**
235: * return a descriptive string.
236: */
237: public String getShortDescription() {
238: return "set/unset variables";
239: }
240:
241: public String getSynopsis(String cmd) {
242: if ("set-var".equals(cmd)) {
243: return cmd + " [<varname> <value>]";
244: } else if ("unset-var".equals(cmd)) {
245: return cmd + " <varname> [<varname> ..]";
246: }
247: return cmd;
248: }
249:
250: public String getLongDescription(String cmd) {
251: String dsc = null;
252: if ("set-var".equals(cmd)) {
253: dsc = "\tWithout parameters, show all variable settings. With\n"
254: + "\tparameters, set variable with name <varname> to <value>.\n"
255: + "\tVariables are expanded in any command you issue on the\n"
256: + "\tcommandline. Variable expansion works like on the shell\n"
257: + "\twith the dollarsign. Both forms, $VARNAME and ${VARNAME},\n"
258: + "\tare supported. If the variable is _not_ set, then the\n"
259: + "\ttext is left untouched. So if there is no variable\n"
260: + "\t$VARNAME, then it is not replaced by an empty string but\n"
261: + "\tstays '$VARNAME'. This is because some scripts use wierd\n"
262: + "\tidentifiers containting dollars (esp. Oracle scripts)\n"
263: + "\tIf you want to quote the dollarsign explicitly, write\n"
264: + "\ttwo dollars: $$FOO means $FOO";
265: } else if ("unset-var".equals(cmd)) {
266: dsc = "\tunset the variable with name <varname>. You may provide\n"
267: + "\tmultiple variables to be unset.";
268: }
269: return dsc;
270: }
271: }
272:
273: /*
274: * Local variables:
275: * c-basic-offset: 4
276: * compile-command: "ant -emacs -find build.xml"
277: * End:
278: */
|