Added: X2UtNamedFormat
Added: SE_CREATE_GLOBAL_NAME constant
This commit is contained in:
parent
5556e69a2d
commit
6d5d37bdf8
183
X2UtNamedFormat.pas
Normal file
183
X2UtNamedFormat.pas
Normal file
@ -0,0 +1,183 @@
|
||||
{
|
||||
:: X2UtNamedFormat implements Format-style functionality using named
|
||||
:: instead of indexed parameters.
|
||||
::
|
||||
:: Last changed: $Date$
|
||||
:: Revision: $Rev$
|
||||
:: Author: $Author$
|
||||
}
|
||||
unit X2UtNamedFormat;
|
||||
|
||||
interface
|
||||
{
|
||||
AFormat uses the same format strings as SysUtils.Format, where each
|
||||
format specifier may use a named instead of a numeric index.
|
||||
|
||||
AParams contains alternating the parameter name and it's value.
|
||||
|
||||
Note: NamedFormat works by mapping names to indices and passing the result
|
||||
to SysUtils.Format. Unnamed specifiers will therefore be affected by
|
||||
named specifiers! It is recommended to name all specifiers.
|
||||
}
|
||||
function NamedFormat(const AFormat: String; AParams: array of const): String;
|
||||
|
||||
|
||||
implementation
|
||||
uses
|
||||
Classes,
|
||||
SysUtils;
|
||||
|
||||
|
||||
type
|
||||
TProtectedMemoryStream = class(TMemoryStream);
|
||||
|
||||
|
||||
const
|
||||
SpecifierChar = '%';
|
||||
ValidNameChars = ['A'..'Z', 'a'..'z', '0'..'9'];
|
||||
|
||||
|
||||
procedure StreamWriteChar(const AStream: TStream; const AValue: Char);
|
||||
begin
|
||||
AStream.WriteBuffer(AValue, SizeOf(Char));
|
||||
end;
|
||||
|
||||
|
||||
procedure StreamWriteString(const AStream: TStream; const AValue: String);
|
||||
begin
|
||||
AStream.WriteBuffer(PChar(AValue)^, Length(AValue));
|
||||
end;
|
||||
|
||||
|
||||
function FindNameEnd(const APosition: PChar; const AEnd: PChar): PChar;
|
||||
var
|
||||
position: PChar;
|
||||
|
||||
begin
|
||||
Result := nil;
|
||||
position := APosition;
|
||||
|
||||
while position < AEnd do
|
||||
begin
|
||||
if position^ = ':' then
|
||||
begin
|
||||
Result := position;
|
||||
break;
|
||||
end;
|
||||
|
||||
if not (position^ in ValidNameChars) then
|
||||
break;
|
||||
|
||||
Inc(position);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function NamedFormat(const AFormat: String; AParams: array of const): String;
|
||||
var
|
||||
currentPos: PChar;
|
||||
formatEnd: PChar;
|
||||
formatStream: TMemoryStream;
|
||||
formatString: String;
|
||||
name: String;
|
||||
nameEnd: PChar;
|
||||
nameStart: PChar;
|
||||
param: TVarRec;
|
||||
paramIndex: Integer;
|
||||
paramNames: TStringList;
|
||||
paramValues: array of TVarRec;
|
||||
specifierIndex: Integer;
|
||||
|
||||
begin
|
||||
if Length(AParams) mod 2 = 1 then
|
||||
raise Exception.Create('AParams must contains a multiple of 2 number of items');
|
||||
|
||||
currentPos := PChar(AFormat);
|
||||
SetLength(paramValues, 0);
|
||||
|
||||
formatEnd := currentPos;
|
||||
Inc(formatEnd, Length(AFormat));
|
||||
|
||||
paramNames := TStringList.Create();
|
||||
try
|
||||
paramNames.CaseSensitive := False;
|
||||
|
||||
formatStream := TMemoryStream.Create();
|
||||
try
|
||||
{ Most likely scenario; the names are longer than the replacement
|
||||
indexes. }
|
||||
TProtectedMemoryStream(formatStream).Capacity := Length(AFormat);
|
||||
|
||||
while currentPos < formatEnd do
|
||||
begin
|
||||
{ Search for % }
|
||||
if currentPos^ = SpecifierChar then
|
||||
begin
|
||||
StreamWriteChar(formatStream, currentPos^);
|
||||
Inc(currentPos);
|
||||
|
||||
{ Check if this is not an escape character }
|
||||
if (currentPos < formatEnd) and (currentPos^ <> SpecifierChar) then
|
||||
begin
|
||||
nameStart := currentPos;
|
||||
nameEnd := FindNameEnd(currentPos, formatEnd);
|
||||
|
||||
if Assigned(nameEnd) then
|
||||
begin
|
||||
SetString(name, nameStart, nameEnd - nameStart);
|
||||
|
||||
specifierIndex := paramNames.IndexOf(name);
|
||||
if specifierIndex = -1 then
|
||||
specifierIndex := paramNames.Add(name);
|
||||
|
||||
StreamWriteString(formatStream, IntToStr(specifierIndex));
|
||||
currentPos := nameEnd;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
StreamWriteChar(formatStream, currentPos^);
|
||||
Inc(currentPos);
|
||||
end;
|
||||
|
||||
SetString(formatString, PChar(formatStream.Memory), formatStream.Size);
|
||||
finally
|
||||
FreeAndNil(formatStream);
|
||||
end;
|
||||
|
||||
SetLength(paramValues, paramNames.Count);
|
||||
paramIndex := 0;
|
||||
|
||||
while paramIndex < High(AParams) do
|
||||
begin
|
||||
param := AParams[paramIndex];
|
||||
|
||||
case param.VType of
|
||||
vtChar: name := param.VChar;
|
||||
vtString: name := param.VString^;
|
||||
vtPChar: name := param.VPChar;
|
||||
vtAnsiString: name := PChar(param.VAnsiString);
|
||||
else
|
||||
raise Exception.CreateFmt('Parameter name at index %d is not a string value',
|
||||
[paramIndex div 2]);
|
||||
end;
|
||||
|
||||
Inc(paramIndex);
|
||||
|
||||
specifierIndex := paramNames.IndexOf(name);
|
||||
if specifierIndex = -1 then
|
||||
raise Exception.CreateFmt('Parameter "%s" could not be found in the format string',
|
||||
[name]);
|
||||
|
||||
paramValues[specifierIndex] := AParams[paramIndex];
|
||||
Inc(paramIndex);
|
||||
end;
|
||||
finally
|
||||
FreeAndNil(paramNames);
|
||||
end;
|
||||
|
||||
Result := Format(formatString, paramValues);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
@ -199,7 +199,8 @@ uses
|
||||
|
||||
|
||||
const
|
||||
WindowClass = 'X2UtSingleInstance.Window';
|
||||
WindowClass = 'X2UtSingleInstance.Window';
|
||||
SE_CREATE_GLOBAL_NAME = 'SeCreateGlobalPrivilege';
|
||||
|
||||
|
||||
var
|
||||
|
Loading…
Reference in New Issue
Block a user