📄 uoptions.pas
字号:
//Gets the topic of an option.
function Topic(Index: Cardinal): String; override;
end;
implementation
{Gets a string representation of the value.
~param Value the value to get the string of
~param Description description of the value (it's type and so on)
~result a string representation }
function ValueToString(const Value: TOptionValue;
const Description: TOptionDescription): String;
const Bools: array[Boolean] of String = ('False', 'True');
var i :Integer; //counter through all items of the set
begin
case Description.DataType of
otString: Result := Value.StrData;
otBoolean: Result := Bools[Value.BoolData];
otInteger: Str(Value.IntData, Result);
otReal: Str(Value.RealData:1:7, Result);
otEnumeration: Result := Description.EnumNames[Value.EnumData];
otSet: begin
Result := '';
if SetUsesShortCuts(Description) then
begin
//for each bit
for i := 0 to Description.SetNames.Count - 1 do
begin
if Value.SetData and (1 shl i) <> 0 then //in the set?
Result := Result + //add its short cut
Char(Description.SetNames.Objects[i]);
end;
Result := UpperCase(Result);
end
else
//for each bit
for i := 0 to Description.SetNames.Count - 1 do
Result := Char(Ord('0') + //add its value
Ord(Value.SetData and (1 shl i) <> 0)) +
Result;
end;
else
assert(False);
end;
end;
{Tries to get the value of an option from its string representation.
~param Str the string representation of an option
~param Value out: the value of the string
~param Description description of the option
~result if the string is a valid value for the option }
function StringToValue(const Str: String; var Value: TOptionValue;
const Description: TOptionDescription): Boolean;
var Error :Integer; //index of the error
Low :String; //the value in lower case
j :Integer; //counter through the characters of the string
begin
case Description.DataType of //parse the string depending on type
otString: begin
Value.StrData := Str;
if (Description.StrMaxLen <> 0) and //string too long?
(Description.StrMaxLen < Length(Str)) then
Delete(Value.StrData, Description.StrMaxLen + 1,
High(Length(Value.StrData))); //truncate it
Result := True;
end;
otBoolean: Result := StringToBoolean(Str, Value.BoolData);
otInteger: begin
Val(Str, Value.IntData, Error);
Result := Error = 0; //is a valid number?
if Result and //check for the bounds
(Description.MinInt <> Description.MaxInt) then
if Value.IntData < Description.MinInt then
Value.IntData := Description.MinInt
else
if Value.IntData > Description.MaxInt then
Value.IntData := Description.MaxInt
end;
otReal: begin
Val(Str, Value.RealData, Error);
Result := Error = 0; //is a valid number?
if Result and //check for the bounds
(Description.MinReal <> Description.MinReal) then
if Value.RealData < Description.MinReal then
Value.RealData := Description.MinReal
else
if Value.RealData > Description.MaxReal then
Value.RealData := Description.MaxReal
end;
otEnumeration: begin //name of an item of the enumeration?
Value.EnumData := Description.EnumNames.IndexOf(Str);
Result := Value.EnumData <> -1;
if not Result then //not a valid name?
begin //try to interpret it as the
Val(Str, Value.EnumData, Error); //index of an item
Result := (Error = 0) and (Value.EnumData >= 0) and
(Value.EnumData < Description.EnumNames.Count);
end;
end;
otSet: begin
Low := Trim(Str);
//valid short cuts defined for the enumeration?
Result := SetUsesShortCuts(Description);
if Result then
begin
Low := LowerCase(Low);
Value.SetData := 0; //set is empty so far
for j := 1 to Length(Low) do //check each character, if
begin //it is a valid short cut
Error := Description.SetNames.IndexOfObject(
TObject(Low[j]));
if Error <> -1 then
Value.SetData := Value.SetData or (1 shl Error)
else
Result := False;
end;
end;
if not Result then //no short cuts?
begin //is a bit-mask
Result := (Low <> '') and
(Length(Low) <= Description.SetNames.Count);
if Result then //correct length?
begin
Value.SetData := 0;
for j := 1 to Length(Low) do //check each character
begin //if it is a binary
Result := Result and (Low[j] in ['0', '1']); //digit
if Low[j] = '1' then //"1" means the item
Value.SetData := Value.SetData or //is in the set
(1 shl (Length(Low) - j));
end;
end;
end;
end;
else
Assert(False);
Result := False;
end;
end;
{Tries to get a boolean value from its string representation.
~param Str the string representation of the boolean value
~param Value out: the value of the string
~result if the string is a valid boolean value }
function StringToBoolean(const Str: String; var Value: Boolean): Boolean;
var IntValue :Integer; //the integer value of the string
Error :Integer; //index of the error
Low :String; //the value in lower case
begin
val(Str, IntValue, Error); //check if it is a number
if Error = 0 then //is a number?
begin
Value := IntValue <> 0; //0 is false
Result := True;
end
else
begin
Low := LowerCase(Str); //get lower case value
Value := (Low = 'on') or //has a "true" meaning?
(Low = 'true') or
(Low = 'yes') or
(Low = 'enable') or
(Low = 'enabled') or
(Low = '1');
Result := Value or (Low = 'off') or //either true or false
(Low = 'false') or
(Low = 'no') or
(Low = 'disable') or
(Low = 'disabled') or
(Low = '0');
end;
end;
type PByte = ^Byte; //type to access a set of size 1 byte
PWORD = ^Word; //type to access a set of size 2 bytes
PDWORD = ^Longword; //type to access a set of size 4 bytes
{Extracts a set to a bit-masked number.
~param TheSet the set
~param SizeOfSet the size of the set
~param BaseIndex ordinal value of the lowest possible item of the set
~result the bit-masked number representing the set }
function SetToOption(const TheSet; SizeOfSet: Integer;
BaseIndex: Integer = 0): TOptionSetType;
begin
case SizeOfSet of
1: Result := PByte(@TheSet)^;
2: Result := PWORD(@TheSet)^;
4: Result := PDWORD(@TheSet)^;
else
raise Exception.Create('Invalid size of set, probably too big!');
end;
Result := Result shr BaseIndex; //adjust set for the base index
end;
{Assigns a bit-masked number to a set.
~param Value the bit-masked number representing the set
~param TheSet the set
~param SizeOfSet the size of the set
~param BaseIndex ordinal value of the lowest possible item of the set }
procedure OptionToSet(Value: TOptionSetType; var TheSet; SizeOfSet: Integer;
BaseIndex: Integer = 0);
begin
Value := Value shl BaseIndex; //adjust set for the base index
case SizeOfSet of
1: PByte(@TheSet)^ := Value;
2: PWORD(@TheSet)^ := Value;
4: PDWORD(@TheSet)^ := Value;
else
raise Exception.Create('Invalid size of set, probably too big!');
end;
end;
{Checks whether the set uses short cuts.
~param Description the description of the set to check
~result if the set uses short cuts }
function SetUsesShortCuts(const Description: TOptionDescription): Boolean;
var i :Integer; //counter through the set
{$IFOPT C+}
j :Integer; //counter to check for valid short cuts
{$ENDIF}
begin
assert(Description.DataType = otSet);
i := Description.SetNames.Count - 1; //for each item, check if it has
assert(i >= 0);
while (i >= 0) and assigned(Description.SetNames.Objects[i]) do //a short cut
begin
{$IFOPT C+}
assert(not (Char(Description.SetNames.Objects[i]) in ['A'..'Z']));
for j := 0 to i - 1 do
assert(Description.SetNames.Objects[i] <> Description.SetNames.Objects[j]);
{$ENDIF}
dec(i); //next option
end;
Result := i < 0; //all items have a short cut?
assert(Result or (i = Description.SetNames.Count - 1));
end;
{Clears the description structure.
~param Description the structure to clear }
procedure ClearDescription(var Description: TOptionDescription);
begin
Description.Name := ''; //free strings
Description.Category := '';
Description.Description := '';
Description.DefaultValue.StrData := '';
FillChar(Description, SizeOf(Description), 0); //clear structure
end;
{ * * * *** * * * *** TOptionWrapper *** * * * *** * * * }
{Returns the current class if the options are loaded in a hierarchy.
~result the actual class }
function TOptionWrapper.GetStartClass: TClass;
begin
raise Exception.Create('No hierarchical loading of options supported!');
end;
{Gets the topic of the options. '' is the default and means no topic is
available.
~result the topic of the options }
function TOptionWrapper.DefaultTopic: String;
begin
if Assigned(FBaseClass) then
Result := GetStartClass.ClassName
else
Result := '';
end;
{Gets the topic of an option. '' is the default and means no topics used.
~param Index index of the option to get the topic of
~result the topic of the option }
function TOptionWrapper.Topic(Index: Cardinal): String;
begin
if Index >= Count then
raise EInvalidOption.Create('Invalid index for option supplied!');
Result := DefaultTopic;
end;
{Gets the index of an option by its name (and type).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -