48fb3296914e6df8fc814e97e0c74af93a9fe274
[org.ibex.xt-crawshaw.git] / src / java / org / ibex / xt / shell / Command.java
1 package org.ibex.xt.shell;
2
3 import java.io.Writer;
4 import java.io.IOException;
5
6 import java.util.*;
7 import java.util.regex.*;
8
9 import org.ibex.js.*;
10 import org.ibex.util.*;
11
12 public abstract class Command {
13     protected Shell shell;
14
15     protected Command(Shell s) { shell = s; }
16
17     /** Returns the command name. */
18     public abstract String name();
19
20     /** Returns a single-line of parameter information, eg. <tt>[pattern]</tt> */
21     public abstract String params();
22
23     /** Returns single-line description of command. */
24     public abstract String summary();
25
26     /** Returns multi-line description. */
27     public abstract String help();
28
29     /** Writes result of execution, even if result is an error. */
30     public abstract void execute(Writer w, String[] args) throws IOException;
31
32
33     /** Returns single-line of usage information, eg. <tt>usage: ls [pattern]</tt> */
34     public void usage(Writer w) throws IOException {
35         w.write("usage: ");
36         w.write(name());
37         w.write(" ");
38         w.write(params());
39         w.write("\n");
40     }
41
42     public List fromShellPath(String s) throws Shell.NoSuchPathException {
43         return fromShellPath(s, null);
44     }
45
46     /** Converts a shell path "/foo/etc/../bar" to its component form,
47      *  { "foo", "bar" } and loads it into the returned list.
48      *  Handles relative positioning to shell.getPath(). */
49     public List fromShellPath(String s, List l) throws Shell.NoSuchPathException {
50         if (s == null) return null;
51         if (l == null) l = new ArrayList();
52
53         s = s.trim().replace("/+", "/");
54         if (s.charAt(0) != '/') l.addAll(Arrays.asList(shell.getPath()));
55
56         StringTokenizer st = new StringTokenizer(s, "/");
57         while (st.hasMoreTokens()) {
58             String part = st.nextToken();
59             if (part == null || part.equals("") || part.equals(".")) continue;
60             else if (part.equals("..")) { if (l.size() > 0) l.remove(l.size() - 1); }
61             else l.add(part);
62         }
63
64         return l;
65     }
66
67     public static class Help extends Command {
68         public Help(Shell s) { super(s); }
69         public String name() { return "help"; }
70         public String params() { return "[command name]"; }
71         public String summary() { return "Lists available commands."; }
72         public String help() { return ""; }
73
74         public void execute(Writer w, String[] c) throws IOException {
75             if (c.length > 1) {
76                 Command cmd = shell.getCommand(c[1]);
77                 if (c == null) {
78                     w.write("help: ");
79                     w.write(c[1]);
80                     w.write(": command not found\n");
81                 } else {
82                     cmd.usage(w);
83                     w.write("\n");
84                     w.write(cmd.help());
85                     w.write("\n");
86                 }
87             } else {
88                 int len = 3;
89                 Command[] cmds = shell.getCommands();
90                 for (int i=0; i < cmds.length; i++)
91                     len = Math.max(cmds[i].name().length(), len);
92
93                 w.write("Available commands:\n");
94                 for (int i=0; i < cmds.length; i++) {
95                     Command cmd = cmds[i];
96                     w.write("  ");
97                     w.write(cmd.name());
98                     for (int j=len - cmd.name().length(); j >= 0; j--) w.write(" ");
99                     w.write(" - ");
100                     w.write(cmd.summary());
101                     w.write("\n");
102                 }
103                 w.write("\nFor usage details, type help [command name].\n");
104             }
105         }
106     }
107
108     public static class Ls extends Command {
109         public Ls(Shell s) { super(s); }
110         public String name() { return "ls"; }
111         public String params() { return "[path]"; }
112         public String summary() { return "List object entries."; }
113         public String help() { return
114             "Lists the keys in an object. Modelled after the UNIX ls command.";
115         }
116
117         public void execute(Writer w, String[] c) throws IOException {
118             if (c.length > 2) { usage(w); return; }
119             String p = c.length == 1 ? "*" : c[1];
120             if (p.endsWith("/")) p += "*";
121
122             try {
123                 List path = fromShellPath(p);
124                 Object key = path.remove(path.size() - 1);
125                 Object po = shell.getFromPath(path.toArray());
126                 if (po == null || !(po instanceof JS))
127                     throw new Shell.NoSuchPathException();
128                 JS cur = (JS)po;
129
130                 if (key instanceof String &&
131                         ((String)key).indexOf('*') >= 0) {
132                     String last = (String)key;
133                     last = last.replaceAll("\\.", "\\.");
134                     last = last.replaceAll("\\*", ".*");
135                     Pattern pat = Pattern.compile(last);
136                     Iterator i = cur.keys().iterator(); while (i.hasNext()) {
137                         Object o = i.next();
138                         if (o == null || !(o instanceof String)) continue;
139                         String s = (String)o;
140                         if (!pat.matcher(s).matches()) continue;
141                         w.write(s);
142                         w.write("\n");
143                     }
144                 } else if (cur.containsKey(key)) {
145                     w.write(key.toString());
146                     w.write("\n");
147                 }
148             } catch (Shell.NoSuchPathException e) {
149                 w.write("error: no such path: ");
150                 w.write(p);
151                 w.write("\n");
152             } catch (JSExn e) {
153                 w.write("error: no such path: ");
154                 w.write(p);
155                 w.write(" (");
156                 w.write(e.getMessage());
157                 w.write(")\n");
158             }
159         }
160     }
161
162     public static class Pwd extends Command {
163         public Pwd(Shell s) { super(s); }
164         public String name() { return "pwd"; }
165         public String params() { return ""; }
166         public String summary() { return "Path to current object."; }
167         public String help() { return "Print the path to the current object."; }
168         public void execute(Writer w, String[] c) throws IOException {
169             if (c.length != 1) { usage(w); return; }
170             Object[] path = shell.getPath();
171             for (int i=0; i < path.length; i++) {
172                 w.write("/");
173                 w.write(path[i].toString());
174             }
175             if (path.length == 0) w.write("/");
176             w.write("\n");
177         }
178     }
179
180     public static class Cd extends Command {
181         public Cd(Shell s) { super(s); }
182         public String name() { return "cd"; }
183         public String params() { return "[path]"; }
184         public String summary() { return "Change current object."; }
185         public String help() { return
186             "Chnages the current object that all other commands use "+
187             "as the base for running.\n Pass either a relative path "+
188             "(e.g. in .prevalent, type cd myob, now in .prevalent.myob) "+
189             "or an absolute path (e.g. cd .prevalent.myob).\n\n" +
190             "To go up one level, cd .. can be used.";
191         }
192         public void execute(Writer w, String[] c) throws IOException {
193             if (c.length > 2) { usage(w); return; }
194             String path = c.length == 1 ? "/" : c[1];
195
196             try { shell.setPath(fromShellPath(path).toArray()); }
197             catch (Shell.NoSuchPathException e) {
198                 w.write("error: no such path: ");
199                 w.write(path);
200                 w.write("\n");
201             }
202         }
203     }
204
205     public static class Rm extends Command {
206         public Rm(Shell s) { super(s); }
207         public String name() { return "rm"; }
208         public String params() { return "[options] [path]"; }
209         public String summary() { return "Removes objects."; }
210         public String help() { return "Removes objects."; } // FIXME
211         public void execute(Writer w, String[] c) throws IOException {
212             if (c.length == 1) { usage(w); return; }
213
214         }
215     }
216 }