-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmessages.pas
129 lines (115 loc) · 4.29 KB
/
messages.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
{$MODE OBJFPC} { -*- delphi -*- }
{$INCLUDE settings.inc}
unit messages;
interface
type
TMessageKind = (mkSuccess, mkNoOp, mkEffect,
mkBogus, mkTooHeavy, mkTooBig, mkNotReachable, mkDuplicate, mkInHole, mkImmovable, mkNoOpening, mkClosed, mkInappropriateTool,
mkCannotTakeBecausePile, mkCannotMoveBecauseLocation, mkCannotMoveBecauseCustom, mkCannotLeaveLocation,
mkCannotFly, mkCannotWalk,
mkNoDoor, mkRedundant, mkBlocked, mkCannotPutOnBecauseInstalled, mkThingsFall, mkAvoidingBurialAlive);
const
mkSuccesses = [mkSuccess, mkNoOp, mkThingsFall];
type
TMessage = record
private
FKind: TMessageKind;
FText: UTF8String;
function GetIsValid(): Boolean;
public
class function Create(): TMessage; static;
constructor Create(const NewKind: TMessageKind; const NewText: UTF8String);
constructor Create(const NewKind: TMessageKind; const Fmt: UTF8String; const Args: array of UTF8String); // [1]
procedure PrefaceFailureTopic(const NewText: UTF8String);
procedure PrefaceFailureTopic(const Fmt: UTF8String; const Args: array of UTF8String); // [1]
property AsKind: TMessageKind read FKind;
property AsText: UTF8String read FText;
property IsValid: Boolean read GetIsValid;
end;
// [1] These APIs assume that Fmt has exactly as many underscores as Args.
// It will crash if this is not the case.
// Therefore, only run it with a trusted Fmt input hard coded to have the right number of underscores.
implementation
// only call this with trusted input as Fmt
function QuickFormat(const Fmt: UTF8String; const Args: array of UTF8String): UTF8String;
var
FmtIndex, ArgIndex, FmtStart, ResultIndex, NewLength, LengthFmt, LengthArg: Cardinal;
begin
Assert(Length(Args) > 0); // otherwise there's no point doing this
LengthFmt := Length(Fmt); // $R-
Assert(Length(Fmt) >= Length(Args));
NewLength := LengthFmt - Length(Args); // $R-
for ArgIndex := Low(Args) to High(Args) do // $R-
Inc(NewLength, Length(Args[ArgIndex]));
SetLength(Result, NewLength); {BOGUS Hint: Function result variable of a managed type does not seem to be initialized}
FmtStart := 1;
FmtIndex := 1;
ArgIndex := Low(Args);
ResultIndex := 1;
while (FmtIndex <= LengthFmt) do
begin
if (Fmt[FmtIndex] = '_') then
begin
if (FmtStart < FmtIndex) then
begin
Move(Fmt[FmtStart], Result[ResultIndex], FmtIndex-FmtStart);
Inc(ResultIndex, FmtIndex-FmtStart);
end;
FmtStart := FmtIndex + 1; // $R-
Assert(ArgIndex <= High(Args));
LengthArg := Length(Args[ArgIndex]); // $R-
if (LengthArg > 0) then
begin
Move(Args[ArgIndex][1], Result[ResultIndex], LengthArg);
Inc(ResultIndex, LengthArg);
end;
Inc(ArgIndex);
if (ArgIndex > High(Args)) then
Break;
end;
Inc(FmtIndex);
end;
Assert(ArgIndex = High(Args)+1);
if (FmtStart <= LengthFmt) then
Move(Fmt[FmtStart], Result[ResultIndex], LengthFmt-FmtStart+1);
Assert(ResultIndex + LengthFmt - FmtStart = Length(Result));
end;
class function TMessage.Create(): TMessage;
begin
Result.FKind := mkSuccess;
Result.FText := '';
end;
constructor TMessage.Create(const NewKind: TMessageKind; const NewText: UTF8String);
begin
Assert(NewText <> '');
FKind := NewKind;
FText := NewText;
end;
constructor TMessage.Create(const NewKind: TMessageKind; const Fmt: UTF8String; const Args: array of UTF8String);
begin
Assert(Fmt <> '');
FKind := NewKind;
FText := QuickFormat(Fmt, Args);
Assert(FText <> '');
end;
procedure TMessage.PrefaceFailureTopic(const NewText: UTF8String);
begin
Assert(not (FKind in mkSuccesses));
Assert(FText <> '');
Assert(NewText <> '');
FText := NewText + ' ' + FText;
end;
procedure TMessage.PrefaceFailureTopic(const Fmt: UTF8String; const Args: array of UTF8String);
begin
Assert(not (FKind in mkSuccesses));
Assert(FText <> '');
Assert(Fmt <> '');
FText := QuickFormat(Fmt, Args) + ' ' + FText;
end;
function TMessage.GetIsValid(): Boolean;
begin
Result := (FKind >= Low(TMessageKind)) and (FKind <= High(TMessageKind));
end;
initialization
//{$INCLUDE registrations/messages.inc}
end.