Merge branch 'master' into x86_64

This commit is contained in:
Alex Smith 2012-08-05 10:33:20 +01:00
commit 284d75bd6a
19 changed files with 688 additions and 32 deletions

View File

@ -168,6 +168,12 @@
#define DP_LANE_STATUS_CR_DONE_B (1 << 4) // Bool
#define DP_LANE_STATUS_CHEQ_DONE_B (1 << 5) // Bool
#define DP_LANE_STATUS_SYMB_LOCK_B (1 << 6) // Bool
#define DP_LANE_STATUS_EQUALIZED_A DP_LANE_STATUS_CR_DONE_A \
|| DP_LANE_STATUS_CHEQ_DONE_A \
|| DP_LANE_STATUS_SYMB_LOCK_A
#define DP_LANE_STATUS_EQUALIZED_B DP_LANE_STATUS_CR_DONE_B \
|| DP_LANE_STATUS_CHEQ_DONE_B \
|| DP_LANE_STATUS_SYMB_LOCK_B
// DP Lane Align Status (0x0204)
#define DP_LANE_ALIGN 0x0204 // Reg
#define DP_LANE_ALIGN_DONE (1 << 0) // Bool

View File

@ -410,6 +410,27 @@ dp_clock_recovery_ok(dp_info* dp)
}
static bool
dp_clock_equalization_ok(dp_info* dp)
{
uint8 laneAlignment
= dp->linkStatus[DP_LANE_ALIGN - DP_LANE_STATUS_0_1];
if ((laneAlignment & DP_LANE_ALIGN_DONE) == 0)
return false;
int lane;
for (lane = 0; lane < dp->laneCount; lane++) {
uint8 laneStatus = dp_get_lane_status(dp, lane);
if ((laneStatus & DP_LANE_STATUS_EQUALIZED_A)
!= DP_LANE_STATUS_EQUALIZED_A) {
return false;
}
}
return true;
}
static void
dp_update_vs_emph(uint32 connectorIndex)
{
@ -612,6 +633,58 @@ dp_link_train_cr(uint32 connectorIndex)
}
status_t
dp_link_train_ce(uint32 connectorIndex)
{
TRACE("%s\n", __func__);
dp_info* dp = &gConnector[connectorIndex]->dpInfo;
// TODO: DisplayPort: Supports TP3?
dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_2);
dp->trainingAttempts = 0;
bool channelEqual = false;
while (1) {
if (dp->trainingReadInterval == 0)
snooze(100);
else
snooze(1000 * 4 * dp->trainingReadInterval);
if (!dp_get_link_status(dp))
break;
if (dp_clock_equalization_ok(dp)) {
channelEqual = true;
break;
}
if (dp->trainingAttempts > 5) {
ERROR("%s: ERROR: failed > 5 times!\n", __func__);
break;
}
dp_get_adjust_train(dp);
dp_update_vs_emph(connectorIndex);
dp->trainingAttempts++;
}
if (!channelEqual) {
ERROR("%s: ERROR: failed\n", __func__);
return B_ERROR;
}
TRACE("%s: channels equalized at voltage %d pre-emphasis %d\n",
__func__, dp->trainingSet[0] & DP_ADJ_VCC_SWING_LANEA_MASK,
(dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
return B_OK;
}
status_t
dp_link_train(uint8 crtcID, display_mode* mode)
{
@ -702,7 +775,7 @@ dp_link_train(uint8 crtcID, display_mode* mode)
dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
dp_link_train_cr(connectorIndex);
// TODO: dp_link_train_ce
dp_link_train_ce(connectorIndex);
// *** DisplayPort link training finish

View File

@ -37,6 +37,7 @@ void dp_setup_connectors();
status_t dp_link_train(uint8 crtcID, display_mode* mode);
status_t dp_link_train_cr(uint32 connectorIndex);
status_t dp_link_train_ce(uint32 connectorIndex);
#endif /* RADEON_HD_DISPLAYPORT_H */

View File

@ -174,6 +174,10 @@ Application Debugger :
# user_interface/cli
CliCommand.cpp
CliContext.cpp
CliContinueCommand.cpp
CliStackTraceCommand.cpp
CliStopCommand.cpp
CliThreadCommand.cpp
CliThreadsCommand.cpp
CliQuitCommand.cpp
CommandLineUserInterface.cpp

View File

@ -6,6 +6,8 @@
#include "CliCommand.h"
#include <stdio.h>
CliCommand::CliCommand(const char* summary, const char* usage)
:
@ -18,3 +20,12 @@ CliCommand::CliCommand(const char* summary, const char* usage)
CliCommand::~CliCommand()
{
}
void
CliCommand::PrintUsage(const char* commandName) const
{
printf("Usage: ");
printf(Usage(), commandName);
printf("\n");
}

View File

@ -21,6 +21,8 @@ public:
const char* Summary() const { return fSummary; }
const char* Usage() const { return fUsage; }
void PrintUsage(const char* commandName) const;
virtual void Execute(int argc, const char* const* argv,
CliContext& context) = 0;

View File

@ -6,6 +6,7 @@
#include "CliContext.h"
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include "UserInterface.h"
@ -19,6 +20,36 @@
static CliContext* sCurrentContext;
// #pragma mark - Event
struct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
Event(int type, Thread* thread = NULL)
:
fType(type),
fThreadReference(thread)
{
}
int Type() const
{
return fType;
}
Thread* GetThread() const
{
return fThreadReference.Get();
}
private:
int fType;
BReference<Thread> fThreadReference;
};
// #pragma mark - CliContext
CliContext::CliContext()
:
fLock("CliContext"),
@ -31,7 +62,8 @@ CliContext::CliContext()
fInputLoopWaitingForEvents(0),
fEventsOccurred(0),
fInputLoopWaiting(false),
fTerminating(false)
fTerminating(false),
fCurrentThread(NULL)
{
sCurrentContext = this;
}
@ -87,6 +119,9 @@ CliContext::Cleanup()
{
Terminating();
while (Event* event = fPendingEvents.RemoveHead())
delete event;
if (fEditLine != NULL) {
el_end(fEditLine);
fEditLine = NULL;
@ -116,6 +151,41 @@ CliContext::Terminating()
}
thread_id
CliContext::CurrentThreadID() const
{
return fCurrentThread != NULL ? fCurrentThread->ID() : -1;
}
void
CliContext::SetCurrentThread(Thread* thread)
{
AutoLocker<BLocker> locker(fLock);
if (fCurrentThread != NULL)
fCurrentThread->ReleaseReference();
fCurrentThread = thread;
if (fCurrentThread != NULL)
fCurrentThread->AcquireReference();
}
void
CliContext::PrintCurrentThread()
{
AutoLocker<Team> teamLocker(fTeam);
if (fCurrentThread != NULL) {
printf("current thread: %" B_PRId32 " \"%s\"\n", fCurrentThread->ID(),
fCurrentThread->Name());
} else
printf("no current thread\n");
}
const char*
CliContext::PromptUser(const char* prompt)
{
@ -126,6 +196,8 @@ CliContext::PromptUser(const char* prompt)
fPrompt = NULL;
ProcessPendingEvents();
return line;
}
@ -155,39 +227,124 @@ CliContext::QuitSession(bool killTeam)
void
CliContext::WaitForThreadOrUser()
{
ProcessPendingEvents();
// TODO: Deal with SIGINT as well!
for (;;) {
_PrepareToWaitForEvents(
EVENT_USER_INTERRUPT | EVENT_THREAD_STATE_CHANGED);
EVENT_USER_INTERRUPT | EVENT_THREAD_STOPPED);
// check whether there are any threads stopped already
thread_id stoppedThread = -1;
Thread* stoppedThread = NULL;
BReference<Thread> stoppedThreadReference;
AutoLocker<Team> teamLocker(fTeam);
for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
Thread* thread = it.Next();) {
if (thread->State() == THREAD_STATE_STOPPED) {
stoppedThread = thread->ID();
stoppedThread = thread;
stoppedThreadReference.SetTo(thread);
break;
}
}
teamLocker.Unlock();
if (stoppedThread >= 0)
_SignalInputLoop(EVENT_THREAD_STATE_CHANGED);
if (stoppedThread != NULL) {
if (fCurrentThread == NULL)
fCurrentThread = stoppedThread;
_SignalInputLoop(EVENT_THREAD_STOPPED);
}
uint32 events = _WaitForEvents();
if ((events & EVENT_QUIT) != 0 || stoppedThread >= 0)
if ((events & EVENT_QUIT) != 0 || stoppedThread != NULL) {
ProcessPendingEvents();
return;
}
}
}
void
CliContext::ThreadStateChanged(const Team::ThreadEvent& event)
CliContext::ProcessPendingEvents()
{
_SignalInputLoop(EVENT_THREAD_STATE_CHANGED);
AutoLocker<Team> teamLocker(fTeam);
for (;;) {
// get the next event
AutoLocker<BLocker> locker(fLock);
Event* event = fPendingEvents.RemoveHead();
locker.Unlock();
if (event == NULL)
break;
ObjectDeleter<Event> eventDeleter(event);
// process the event
Thread* thread = event->GetThread();
switch (event->Type()) {
case EVENT_QUIT:
case EVENT_USER_INTERRUPT:
break;
case EVENT_THREAD_ADDED:
printf("[new thread: %" B_PRId32 " \"%s\"]\n", thread->ID(),
thread->Name());
break;
case EVENT_THREAD_REMOVED:
printf("[thread terminated: %" B_PRId32 " \"%s\"]\n",
thread->ID(), thread->Name());
break;
case EVENT_THREAD_STOPPED:
printf("[thread stopped: %" B_PRId32 " \"%s\"]\n",
thread->ID(), thread->Name());
break;
}
}
}
void
CliContext::ThreadAdded(const Team::ThreadEvent& threadEvent)
{
_QueueEvent(
new(std::nothrow) Event(EVENT_THREAD_ADDED, threadEvent.GetThread()));
_SignalInputLoop(EVENT_THREAD_ADDED);
}
void
CliContext::ThreadRemoved(const Team::ThreadEvent& threadEvent)
{
_QueueEvent(
new(std::nothrow) Event(EVENT_THREAD_REMOVED, threadEvent.GetThread()));
_SignalInputLoop(EVENT_THREAD_REMOVED);
}
void
CliContext::ThreadStateChanged(const Team::ThreadEvent& threadEvent)
{
if (threadEvent.GetThread()->State() != THREAD_STATE_STOPPED)
return;
_QueueEvent(
new(std::nothrow) Event(EVENT_THREAD_STOPPED, threadEvent.GetThread()));
_SignalInputLoop(EVENT_THREAD_STOPPED);
}
void
CliContext::_QueueEvent(Event* event)
{
if (event == NULL) {
// no memory -- can't do anything about it
return;
}
AutoLocker<BLocker> locker(fLock);
fPendingEvents.Add(event);
}

View File

@ -24,7 +24,9 @@ public:
enum {
EVENT_QUIT = 0x01,
EVENT_USER_INTERRUPT = 0x02,
EVENT_THREAD_STATE_CHANGED = 0x04,
EVENT_THREAD_ADDED = 0x04,
EVENT_THREAD_REMOVED = 0x08,
EVENT_THREAD_STOPPED = 0x10,
};
public:
@ -37,9 +39,18 @@ public:
void Terminating();
bool IsTerminating() const { return fTerminating; }
// service methods for the input loop thread follow
Team* GetTeam() const { return fTeam; }
UserInterfaceListener* GetUserInterfaceListener() const
{ return fListener; }
Thread* CurrentThread() const { return fCurrentThread; }
thread_id CurrentThreadID() const;
void SetCurrentThread(Thread* thread);
void PrintCurrentThread();
const char* PromptUser(const char* prompt);
void AddLineToInputHistory(const char* line);
@ -47,13 +58,24 @@ public:
void QuitSession(bool killTeam);
void WaitForThreadOrUser();
void ProcessPendingEvents();
private:
struct Event;
typedef DoublyLinkedList<Event> EventList;
private:
// Team::Listener
virtual void ThreadAdded(const Team::ThreadEvent& event);
virtual void ThreadRemoved(const Team::ThreadEvent& event);
virtual void ThreadStateChanged(
const Team::ThreadEvent& event);
private:
void _QueueEvent(Event* event);
void _PrepareToWaitForEvents(uint32 eventMask);
uint32 _WaitForEvents();
void _SignalInputLoop(uint32 events);
@ -72,6 +94,10 @@ private:
uint32 fEventsOccurred;
bool fInputLoopWaiting;
volatile bool fTerminating;
Thread* fCurrentThread;
EventList fPendingEvents;
};

View File

@ -0,0 +1,45 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "CliContinueCommand.h"
#include <stdio.h>
#include <AutoLocker.h>
#include "CliContext.h"
#include "MessageCodes.h"
#include "Team.h"
#include "UserInterface.h"
CliContinueCommand::CliContinueCommand()
:
CliCommand("continue the current thread",
"%s\n"
"Continues the current thread.")
{
}
void
CliContinueCommand::Execute(int argc, const char* const* argv,
CliContext& context)
{
AutoLocker<Team> teamLocker(context.GetTeam());
Thread* thread = context.CurrentThread();
if (thread == NULL) {
printf("Error: No current thread.\n");
return;
}
if (thread->State() != THREAD_STATE_STOPPED) {
printf("Error: The current thread is not stopped.\n");
return;
}
context.GetUserInterfaceListener()->ThreadActionRequested(thread->ID(),
MSG_THREAD_RUN);
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef CLI_CONTINUE_COMMAND_H
#define CLI_CONTINUE_COMMAND_H
#include "CliCommand.h"
class CliContinueCommand : public CliCommand {
public:
CliContinueCommand();
virtual void Execute(int argc, const char* const* argv,
CliContext& context);
};
#endif // CLI_CONTINUE_COMMAND_H

View File

@ -43,7 +43,7 @@ CliQuitCommand::Execute(int argc, const char* const* argv, CliContext& context)
break;
}
if (trimmedLine == "d")
if (trimmedLine == "c")
break;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "CliStackTraceCommand.h"
#include <stdio.h>
#include <AutoLocker.h>
#include "CliContext.h"
#include "FunctionInstance.h"
#include "StackTrace.h"
#include "Team.h"
CliStackTraceCommand::CliStackTraceCommand()
:
CliCommand("print a stack trace of the current thread",
"%s\n"
"Prints a stack trace for the current thread.")
{
}
void
CliStackTraceCommand::Execute(int argc, const char* const* argv,
CliContext& context)
{
// get the current thread
Team* team = context.GetTeam();
AutoLocker<Team> teamLocker(team);
Thread* thread = context.CurrentThread();
if (thread == NULL) {
printf("no current thread\n");
return;
}
if (thread->State() != THREAD_STATE_STOPPED) {
printf("Current thread is not stopped. Can't get stack trace.\n");
return;
}
// get its stack trace
StackTrace* stackTrace = thread->GetStackTrace();
if (stackTrace == NULL) {
// TODO: Wait for stack trace!
printf("Current thread doesn't have a stack trace. Waiting not "
"implemented yet\n");
return;
}
BReference<StackTrace> stackTraceReference(stackTrace);
// hold a reference until we're done
teamLocker.Unlock();
// print the stack trace
int32 frameCount = stackTrace->CountFrames();
for (int32 i = 0; i < frameCount; i++) {
StackFrame* frame = stackTrace->FrameAt(i);
printf("%3" B_PRId32 " %#" B_PRIx64 " %#" B_PRIx64, i,
(uint64)frame->FrameAddress(), (uint64)frame->InstructionPointer());
Image* image = frame->GetImage();
FunctionInstance* function = frame->Function();
if (image == NULL && function == NULL) {
printf(" ???\n");
continue;
}
BString name;
target_addr_t baseAddress;
if (function != NULL) {
name = function->PrettyName();
baseAddress = function->Address();
} else {
name = image->Name();
baseAddress = image->Info().TextBase();
}
printf(" %s + %#" B_PRIx64 "\n", name.String(),
uint64(frame->InstructionPointer() - baseAddress));
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef CLI_STACK_TRACE_COMMAND_H
#define CLI_STACK_TRACE_COMMAND_H
#include "CliCommand.h"
class CliStackTraceCommand : public CliCommand {
public:
CliStackTraceCommand();
virtual void Execute(int argc, const char* const* argv,
CliContext& context);
};
#endif // CLI_STACK_TRACE_COMMAND_H

View File

@ -0,0 +1,45 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "CliStopCommand.h"
#include <stdio.h>
#include <AutoLocker.h>
#include "CliContext.h"
#include "MessageCodes.h"
#include "Team.h"
#include "UserInterface.h"
CliStopCommand::CliStopCommand()
:
CliCommand("stop the current thread",
"%s\n"
"Stops the current thread.")
{
}
void
CliStopCommand::Execute(int argc, const char* const* argv,
CliContext& context)
{
AutoLocker<Team> teamLocker(context.GetTeam());
Thread* thread = context.CurrentThread();
if (thread == NULL) {
printf("Error: No current thread.\n");
return;
}
if (thread->State() == THREAD_STATE_STOPPED) {
printf("Error: The current thread is already stopped.\n");
return;
}
context.GetUserInterfaceListener()->ThreadActionRequested(thread->ID(),
MSG_THREAD_STOP);
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef CLI_STOP_COMMAND_H
#define CLI_STOP_COMMAND_H
#include "CliCommand.h"
class CliStopCommand : public CliCommand {
public:
CliStopCommand();
virtual void Execute(int argc, const char* const* argv,
CliContext& context);
};
#endif // CLI_STOP_COMMAND_H

View File

@ -0,0 +1,58 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "CliThreadCommand.h"
#include <stdio.h>
#include <AutoLocker.h>
#include "CliContext.h"
#include "Team.h"
CliThreadCommand::CliThreadCommand()
:
CliCommand("set or print the current thread",
"%s [ <thread ID> ]\n"
"Sets the current thread to <thread ID>, if supplied. Otherwise prints "
"the\n"
"current thread.")
{
}
void
CliThreadCommand::Execute(int argc, const char* const* argv,
CliContext& context)
{
if (argc > 2) {
PrintUsage(argv[0]);
return;
}
if (argc < 2) {
// no arguments -- print the current thread
context.PrintCurrentThread();
return;
}
// parse the argument
char* endPointer;
long threadID = strtol(argv[1], &endPointer, 0);
if (*endPointer != '\0' || threadID < 0) {
printf("Error: Invalid parameter \"%s\"\n", argv[1]);
return;
}
// get the thread and change the current thread
Team* team = context.GetTeam();
AutoLocker<Team> teamLocker(team);
if (Thread* thread = team->ThreadByID(threadID))
context.SetCurrentThread(thread);
else
printf("Error: No thread with ID %ld\n", threadID);
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef CLI_THREAD_COMMAND_H
#define CLI_THREAD_COMMAND_H
#include "CliCommand.h"
class CliThreadCommand : public CliCommand {
public:
CliThreadCommand();
virtual void Execute(int argc, const char* const* argv,
CliContext& context);
};
#endif // CLI_THREAD_COMMAND_H

View File

@ -16,7 +16,11 @@
#include <Referenceable.h>
#include "CliContext.h"
#include "CliContinueCommand.h"
#include "CliQuitCommand.h"
#include "CliStackTraceCommand.h"
#include "CliStopCommand.h"
#include "CliThreadCommand.h"
#include "CliThreadsCommand.h"
@ -56,16 +60,23 @@ private:
struct CommandLineUserInterface::HelpCommand : CliCommand {
HelpCommand(CommandLineUserInterface* userInterface)
:
CliCommand("print a list of all commands",
"%s\n"
"Prints a list of all commands."),
CliCommand("print help for a command or a list of all commands",
"%s [ <command> ]\n"
"Prints help for command <command>, if given, or a list of all "
"commands\n"
"otherwise."),
fUserInterface(userInterface)
{
}
virtual void Execute(int argc, const char* const* argv, CliContext& context)
{
fUserInterface->_PrintHelp();
if (argc > 2) {
PrintUsage(argv[0]);
return;
}
fUserInterface->_PrintHelp(argc == 2 ? argv[1] : NULL);
}
private:
@ -207,9 +218,19 @@ CommandLineUserInterface::_InputLoopEntry(void* data)
status_t
CommandLineUserInterface::_InputLoop()
{
thread_id currentThread = -1;
while (!fTerminating) {
// Wait for a thread or Ctrl-C.
fContext.WaitForThreadOrUser();
if (fContext.IsTerminating())
break;
// Print the active thread, if it changed.
if (fContext.CurrentThreadID() != currentThread) {
fContext.PrintCurrentThread();
currentThread = fContext.CurrentThreadID();
}
// read a command line
const char* line = fContext.PromptUser(kDebuggerPrompt);
@ -251,8 +272,18 @@ CommandLineUserInterface::_InputLoop()
status_t
CommandLineUserInterface::_RegisterCommands()
{
if (_RegisterCommand("help", new(std::nothrow) HelpCommand(this)) &&
BReference<CliCommand> stackTraceCommandReference(
new(std::nothrow) CliStackTraceCommand, true);
BReference<CliCommand> stackTraceCommandReference2(
stackTraceCommandReference.Get());
if (_RegisterCommand("bt", stackTraceCommandReference.Detach()) &&
_RegisterCommand("continue", new(std::nothrow) CliContinueCommand) &&
_RegisterCommand("help", new(std::nothrow) HelpCommand(this)) &&
_RegisterCommand("quit", new(std::nothrow) CliQuitCommand) &&
_RegisterCommand("sc", stackTraceCommandReference2.Detach()) &&
_RegisterCommand("stop", new(std::nothrow) CliStopCommand) &&
_RegisterCommand("thread", new(std::nothrow) CliThreadCommand) &&
_RegisterCommand("threads", new(std::nothrow) CliThreadsCommand)) {
return B_OK;
}
@ -282,33 +313,63 @@ CommandLineUserInterface::_RegisterCommand(const BString& name,
void
CommandLineUserInterface::_ExecuteCommand(int argc, const char* const* argv)
{
const char* commandName = argv[0];
CommandEntry* commandEntry = _FindCommand(argv[0]);
if (commandEntry != NULL)
commandEntry->Command()->Execute(argc, argv, fContext);
}
CommandLineUserInterface::CommandEntry*
CommandLineUserInterface::_FindCommand(const char* commandName)
{
size_t commandNameLength = strlen(commandName);
CommandEntry* firstEntry = NULL;
// try to find an exact match first
CommandEntry* commandEntry = NULL;
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {
if (entry->Name() == commandName) {
commandEntry = entry;
break;
}
}
// If nothing found yet, try partial matches, but only, if they are
// unambiguous.
if (commandEntry == NULL) {
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {
if (entry->Name().Compare(commandName, commandNameLength) == 0) {
if (firstEntry != NULL) {
printf("Ambiguous command \"%s\".\n", commandName);
return;
if (commandEntry != NULL) {
printf("Error: Ambiguous command \"%s\".\n", commandName);
return NULL;
}
firstEntry = entry;
commandEntry = entry;
}
}
}
if (firstEntry == NULL) {
printf("Unknown command \"%s\".\n", commandName);
return;
if (commandEntry == NULL) {
printf("Error: Unknown command \"%s\".\n", commandName);
return NULL;
}
firstEntry->Command()->Execute(argc, argv, fContext);
return commandEntry;
}
void
CommandLineUserInterface::_PrintHelp()
CommandLineUserInterface::_PrintHelp(const char* commandName)
{
// If a command name is given, print the usage for that one.
if (commandName != NULL) {
CommandEntry* commandEntry = _FindCommand(commandName);
if (commandEntry != NULL)
commandEntry->Command()->PrintUsage(commandEntry->Name().String());
return;
}
// No command name given -- print a list of all commands.
// determine longest command name
int32 longestCommandName = 0;
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {

View File

@ -64,7 +64,8 @@ private:
CliCommand* command);
void _ExecuteCommand(int argc,
const char* const* argv);
void _PrintHelp();
CommandEntry* _FindCommand(const char* commandName);
void _PrintHelp(const char* commandName);
private:
CliContext fContext;