Files
llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp
Greg Clayton 3bcdfc0ec1 <rdar://problem/12798131>
Cleaned up the option parsing code to always pass around the short options as integers. Previously we cast this down to "char" and lost some information. I recently added an assert that would detect duplicate short character options which was firing during the test suite.

This fix does the following:
- make sure all short options are treated as "int"
- make sure that short options can be non-printable values when a short option is not required or when an option group is mixed into many commands and a short option is not desired
- fix the help printing to "do the right thing" in all cases. Previously if there were duplicate short character options, it would just not emit help for the duplicates
- fix option parsing when there are duplicates to parse options correctly. Previously the option parsing, when done for an OptionGroup, would just start parsing options incorrectly by omitting table entries and it would end up setting the wrong option value

llvm-svn: 169189
2012-12-04 00:32:51 +00:00

234 lines
8.8 KiB
C++

//===-- OptionGroupFormat.cpp -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Interpreter/OptionGroupFormat.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Utility/Utils.h"
using namespace lldb;
using namespace lldb_private;
OptionGroupFormat::OptionGroupFormat (lldb::Format default_format,
uint64_t default_byte_size,
uint64_t default_count) :
m_format (default_format, default_format),
m_byte_size (default_byte_size, default_byte_size),
m_count (default_count, default_count),
m_prev_gdb_format('x'),
m_prev_gdb_size('w')
{
}
OptionGroupFormat::~OptionGroupFormat ()
{
}
static OptionDefinition
g_option_table[] =
{
{ LLDB_OPT_SET_1, false, "format" ,'f', required_argument, NULL, 0, eArgTypeFormat , "Specify a format to be used for display."},
{ LLDB_OPT_SET_2, false, "gdb-format",'G', required_argument, NULL, 0, eArgTypeGDBFormat, "Specify a format using a GDB format specifier string."},
{ LLDB_OPT_SET_3, false, "size" ,'s', required_argument, NULL, 0, eArgTypeByteSize , "The size in bytes to use when displaying with the selected format."},
{ LLDB_OPT_SET_4, false, "count" ,'c', required_argument, NULL, 0, eArgTypeCount , "The number of total items to display."},
};
uint32_t
OptionGroupFormat::GetNumDefinitions ()
{
if (m_byte_size.GetDefaultValue() < UINT64_MAX)
{
if (m_count.GetDefaultValue() < UINT64_MAX)
return 4;
else
return 3;
}
return 2;
}
const OptionDefinition *
OptionGroupFormat::GetDefinitions ()
{
return g_option_table;
}
Error
OptionGroupFormat::SetOptionValue (CommandInterpreter &interpreter,
uint32_t option_idx,
const char *option_arg)
{
Error error;
const int short_option = g_option_table[option_idx].short_option;
switch (short_option)
{
case 'f':
error = m_format.SetValueFromCString (option_arg);
break;
case 'c':
if (m_count.GetDefaultValue() == 0)
{
error.SetErrorString ("--count option is disabled");
}
else
{
error = m_count.SetValueFromCString (option_arg);
if (m_count.GetCurrentValue() == 0)
error.SetErrorStringWithFormat("invalid --count option value '%s'", option_arg);
}
break;
case 's':
if (m_byte_size.GetDefaultValue() == 0)
{
error.SetErrorString ("--size option is disabled");
}
else
{
error = m_byte_size.SetValueFromCString (option_arg);
if (m_byte_size.GetCurrentValue() == 0)
error.SetErrorStringWithFormat("invalid --size option value '%s'", option_arg);
}
break;
case 'G':
{
char *end = NULL;
const char *gdb_format_cstr = option_arg;
uint64_t count = 0;
if (::isdigit (gdb_format_cstr[0]))
{
count = strtoull (gdb_format_cstr, &end, 0);
if (option_arg != end)
gdb_format_cstr = end; // We have a valid count, advance the string position
else
count = 0;
}
Format format = eFormatDefault;
uint32_t byte_size = 0;
while (ParserGDBFormatLetter (gdb_format_cstr[0], format, byte_size))
{
++gdb_format_cstr;
}
// We the first character of the "gdb_format_cstr" is not the
// NULL terminator, we didn't consume the entire string and
// something is wrong. Also, if none of the format, size or count
// was specified correctly, then abort.
if (gdb_format_cstr[0] || (format == eFormatInvalid && byte_size == 0 && count == 0))
{
// Nothing got set correctly
error.SetErrorStringWithFormat ("invalid gdb format string '%s'", option_arg);
return error;
}
// At least one of the format, size or count was set correctly.
// Anything that wasn't set correctly should be set to the
// previous default
if (format == eFormatInvalid)
ParserGDBFormatLetter (m_prev_gdb_format, format, byte_size);
const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX;
const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX;
if (byte_size_enabled)
{
// Byte size is enabled
if (byte_size == 0)
ParserGDBFormatLetter (m_prev_gdb_size, format, byte_size);
}
else
{
// Byte size is disabled, make sure it wasn't specified
if (byte_size > 0)
{
error.SetErrorString ("this command doesn't support specifying a byte size");
return error;
}
}
if (count_enabled)
{
// Count is enabled and was not set, set it to the default for gdb format statements (which is 1).
if (count == 0)
count = 1;
}
else
{
// Count is disabled, make sure it wasn't specified
if (count > 0)
{
error.SetErrorString ("this command doesn't support specifying a count");
return error;
}
}
m_format.SetCurrentValue (format);
m_format.SetOptionWasSet ();
if (byte_size_enabled)
{
m_byte_size.SetCurrentValue (byte_size);
m_byte_size.SetOptionWasSet ();
}
if (count_enabled)
{
m_count.SetCurrentValue(count);
m_count.SetOptionWasSet ();
}
}
break;
default:
error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
break;
}
return error;
}
bool
OptionGroupFormat::ParserGDBFormatLetter (char format_letter, Format &format, uint32_t &byte_size)
{
switch (format_letter)
{
case 'o': format = eFormatOctal; m_prev_gdb_format = format_letter; return true;
case 'x': format = eFormatHex; m_prev_gdb_format = format_letter; return true;
case 'd': format = eFormatDecimal; m_prev_gdb_format = format_letter; return true;
case 'u': format = eFormatUnsigned; m_prev_gdb_format = format_letter; return true;
case 't': format = eFormatBinary; m_prev_gdb_format = format_letter; return true;
case 'f': format = eFormatFloat; m_prev_gdb_format = format_letter; return true;
case 'a': format = eFormatAddressInfo; m_prev_gdb_format = format_letter; return true;
case 'i': format = eFormatInstruction; m_prev_gdb_format = format_letter; return true;
case 'c': format = eFormatChar; m_prev_gdb_format = format_letter; return true;
case 's': format = eFormatCString; m_prev_gdb_format = format_letter; return true;
case 'T': format = eFormatOSType; m_prev_gdb_format = format_letter; return true;
case 'A': format = eFormatHexFloat; m_prev_gdb_format = format_letter; return true;
case 'b': byte_size = 1; m_prev_gdb_size = format_letter; return true;
case 'h': byte_size = 2; m_prev_gdb_size = format_letter; return true;
case 'w': byte_size = 4; m_prev_gdb_size = format_letter; return true;
case 'g': byte_size = 8; m_prev_gdb_size = format_letter; return true;
default: break;
}
return false;
}
void
OptionGroupFormat::OptionParsingStarting (CommandInterpreter &interpreter)
{
m_format.Clear();
m_byte_size.Clear();
m_count.Clear();
}