/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.debugger;
import java.io.PrintStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
import org.jnode.driver.ApiNotFoundException;
import org.jnode.driver.Device;
import org.jnode.driver.DeviceUtils;
import org.jnode.driver.input.KeyboardAPI;
import org.jnode.driver.input.KeyboardEvent;
import org.jnode.driver.input.KeyboardListener;
import org.jnode.driver.input.SystemTriggerListener;
import org.jnode.system.event.SystemEvent;
import org.jnode.vm.VmSystem;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public class Debugger implements SystemTriggerListener, KeyboardListener,
PrivilegedAction<Void> {
private boolean enabled;
private KeyboardEvent event;
private DebugState state;
/**
* @see org.jnode.driver.input.SystemTriggerListener#systemTrigger(org.jnode.system.event.SystemEvent)
*/
public void systemTrigger(SystemEvent event) {
event.consume();
if (!enabled) {
// Entering debugger
reset();
setPreferredListener();
VmSystem.getOut().println("[Debugger ('h' for help)]");
} else {
// Exiting debugger
System.out.println(); // Trigger a screen update
}
enabled = !enabled;
}
/**
* @see org.jnode.driver.input.KeyboardListener#keyPressed(org.jnode.driver.input.KeyboardEvent)
*/
public void keyPressed(KeyboardEvent event) {
if (enabled) {
this.event = event;
AccessController.doPrivileged(this);
event.consume();
}
}
/**
* @see org.jnode.driver.input.KeyboardListener#keyReleased(org.jnode.driver.input.KeyboardEvent)
*/
public void keyReleased(KeyboardEvent event) {
if (enabled) {
// Do nothing
event.consume();
}
}
/**
* Perform the actual debugger actions.
*
* @see java.security.PrivilegedAction#run()
*/
public Void run() {
final PrintStream out = VmSystem.getOut();
DebugState st = this.state;
while ((st != null) && (!event.isConsumed())) {
final DebugState newState = st.process(event);
if (event.isConsumed()) {
newState.print(out);
this.state = newState;
out.println();
} else {
st = st.getParent();
}
}
if (!event.isConsumed()) {
switch (event.getKeyChar()) {
case 'p':
state.print(out);
out.println();
break;
case '.':
out.println("State trace:");
out.println(state.getStateTrace());
out.println();
break;
case 'h':
case '?':
case 'H':
help(out);
}
}
return null;
}
private void help(PrintStream out) {
out.println("Usage:");
final TreeMap<String, String> map = new TreeMap<String, String>();
map.put(".", "Print state trace");
map.put("p", "Print current state");
map.put("h", "Print usage information");
state.fillHelp(map);
for (Map.Entry<String, String> entry : map.entrySet()) {
out.println(entry.getKey() + " - " + entry.getValue());
}
out.println();
}
private void setPreferredListener() {
final KeyboardListener l = this;
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
try {
final Collection<Device> devs = DeviceUtils
.getDevicesByAPI(KeyboardAPI.class);
for (Device dev : devs) {
final KeyboardAPI api = dev.getAPI(KeyboardAPI.class);
api.setPreferredListener(l);
}
} catch (ApiNotFoundException ex) {
// Ignore
}
return null;
}
});
}
private void reset() {
state = new RootState();
}
}