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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
|
asjgfsdkjsfld
{ Resource Unit
Programmer: Brad Williams
BitSoft Development, L.L.C.
Copyright (c) 1996
Version 1.1
Revision History
1.1 (12/26/97)
- updated to add cdResource directive so that can use standard TStringList
resources created by TVRW and TVDT
1.0
- original implementation }
unit Resource;
interface
{
The Resource unit provides global variables which are used to build and
access resource files. InitRez must always be called before accessing any
variables in the Resource unit. The programmer should also always call
Done to free all file handles allocated to the program.
}
{$i platform.inc}
{$ifdef PPC_FPC}
{$H-}
{$else}
{$F+,O+,E+,N+}
{$endif}
{$X+,R-,I-,Q-,V-}
{$ifndef OS_UNIX}
{$S-}
{$endif}
uses
FVConsts, Objects, Dos;
const
RezExt: ExtStr = '.RES';
{ The file extension used on all resource files. }
RezBufferSize: Word = 4096;
{ RezBufferSize is the number of bytes to use for the resource file's
stream's buffer. RezBufferSize is passed to TBufStream.Init. }
{ reXXXX constants are used with resource files to retrieve the standard
Free Vision dialogs. The constant is followed by the Unit in which it
is used and the resource which is stored separated by a period. }
reChDirDialog = 'ChDirDialog'; { StdDlg.TChDirDialog }
reEditChDirDialog = 'EditChDirDialog'; { StdDlg.TEditChDirDialog }
reFindTextDlg = 'FindTextDlg'; { Editors.CreateFindDialog }
reHints = 'Hints'; { Resource.Hints }
reJumpLineDlg = 'JumpLineDlg'; { Editors.MakeJumpLineDlg }
reLabels = 'Labels'; { Resource.Labels }
reMenuBar = 'MenuBar'; { App.MenuBar }
reOpenDlg = 'OpenDlg'; { StdDlg.TFileDialog - Open }
reReformDocDlg = 'ReformDocDlg'; { Editors.MakeReformDocDlg }
reReplaceDlg = 'ReplaceDlg'; { Editors.CreateReplaceDialog }
reRightMarginDlg = 'RightMarginDlg'; { Editors.MakeRightMarginDlg }
reStatusLine = 'StatusLine'; { App.StatusLine }
reStrings = 'Strings'; { Resource.Strings }
reSaveAsDlg = 'SaveAsDlg'; { StdDlg.TFileDialog - Save As }
reTabStopDlg = 'TabStopDlg'; { Editors.MakeTabStopDlg }
reWindowListDlg = 'WindowListDlg'; { Editors.MakeWindowListDlg }
reAboutDlg = 'About'; { App unit about dialog }
{$I str.inc}
{ STR.INC declares all the string list constants used in the standard
Free Vision library units. They are placed in a separate file as a
template for use by the resource file generator, MakeRez.
Applications which use resource files and need to add strings of their
own should use STR.INC as the start for the resource file.
See MakeRez.PAS for more information about generating resource files.}
type
PConstant = ^TConstant;
TConstant = object(TObject)
Value: Word;
{ The value assigned to the constant. }
constructor Init (AValue: Word; AText: string);
{ Init assigns AValue to Value to AText to Text. AText may be an empty
string.
If an error occurs Init fails. }
destructor Done; virtual;
{ Done disposes of Text then calls the inherited destructor. }
procedure SetText (AText: string);
{ SetText changes FText to the word equivalent of AText. }
procedure SetValue (AValue: string);
{ SetValue changes Value to the word equivalent of AValue. }
function Text: string;
{ Text returns a string equivalent to FText. If FText is nil, an
empty string is returned. }
function ValueAsString: string;
{ ValueAsString returns the string equivalent of Value. }
private
FText: PString;
{ The text to display for the constant. }
end; { of TConstant }
PMemStringList = ^TMemStringList;
TMemStringList = object(TSortedCollection)
{ A TMemStringList combines the functions of a TStrListMaker and a
TStringList into one object, allowing generation and use of string
lists in the same application. TMemStringList is fully compatible
with string lists created using TStrListMaker, so legacy applications
will work without problems.
When using a string list in the same program as it is created, a
resource file is not required. This allows language independant coding
of units without the need for conditional defines and recompiling. }
constructor Init;
{ Creates an empty, in-memory string list that is not associated with a
resource file. }
constructor Load (var S: TStream);
{ Load creates a TStringList from which it gets its strings upon a call
to Get. The strings on the resource file may be loaded into memory
for editing by calling LoadList.
If initialized with Load, the stream must remain valid for the life
of this object. }
destructor Done; virtual;
{ Done deallocates the memory allocated to the string list. }
function Compare (Key1, Key2: Pointer): Sw_Integer; virtual;
{ Compare assumes Key1 and Key2 are Word values and returns:
-1 if Key1 < Key2
0 if Key1 = Key2
1 if Key1 > Key2 }
function Get (Key: Word): String; virtual;
{ GetKey searches for a string with a key matching Key and returns it.
An empty string is returned if a string with a matching Key is not
found.
If Count > 0, the in memory collection is searched. If List^.Count
is 0, the inherited Get method is called. }
procedure Insert (Item: Pointer); virtual;
{ If Item is not nil, Insert attempts to insert the item into the
collection. If a collection expansion error occurs Insert disposes
of Item by calling FreeItem.
Item must be a pointer to a TConstant or its descendant. }
function KeyOf (Item: Pointer): Pointer; virtual;
{ KeyOf returns a pointer to TConstant.Value. }
function LoadStrings: Sw_Integer;
{ LoadStrings reads all strings the associated resource file into
memory, places them in the collection, and returns 0.
If an error occurs LoadStrings returns the stream status error code
or a DOS error code. Possible DOS error codes include:
2: no associated resource file
8: out of memory }
function NewConstant (Value: Word; S: string): PConstant; virtual;
{ NewConstant is called by LoadStrings. }
procedure Put (Key: Word; S: String); virtual;
{ Put creates a new PConstant containing Key and Word then calls
Insert to place it in the collection. }
procedure Store (var S: TStream);
{ Store creates a TStrListMaker, fills it with the items in List,
writes the TStrListMaker to the stream by calling
TStrListMaker.Store, then disposes of the TStrListMaker. }
private
StringList: PStringList;
end; { of TMemStringList) }
var
{$ifdef cdResource}
Hints: PStringList;
{$else}
Hints: PMemStringList;
{$endif cdResource}
{ Hints is a string list for use within the application to provide
context sensitive help on the command line. Hints is always used in
the application. }
{$ifdef cdResource}
Strings: PStringList;
{$else}
Strings: PMemStringList;
{$endif cdResource}
{ Strings holds messages such as errors and general information that are
displayed at run-time, normally with MessageBox. Strings is always
used in the application. }
{$ifdef cdResource}
Labels: PStringList;
{$else}
Labels: PMemStringList;
{$endif cdResource}
{ Labels is a string list for use within the application when a
resource file is not used, or when creating a resource file. Labels
contains all text used in dialog titles, labels, buttons, menus,
statuslines, etc., used in the application which can be burned into
language specific resources. It does not contain any messages
displayed at run-time using MessageBox or the status line hints.
Using the Labels variable when creating views allows language
independant coding of views such as the MessageBox, StdDlg and Editors
units. }
RezFile: PResourceFile;
{ RezFile is a global variable used when the Free Vision library
is compiled using the cdResource conditional define, or when creating
resource files.
All standard Free Vision application resources are accessed from the
resource file using the reXXXX constants. Modify the STR.INC under a
new file name to create new language specific resource files. See the
MakeRez program file for more information. }
procedure DoneResource;
{ Done destructs all objects initialized in this unit and frees all
allocated heap. }
{$ifndef cdResource}
function InitResource: Boolean;
{$endif cdResource}
{ Init initializes the Hints and Strings for use with in memory strings
lists. Init should be used in applications which do not use a resource
file, or when creating resource files. }
{$ifdef cdResource}
function InitRezFile (AFile: FNameStr; Mode: Word;
var AResFile: PResourceFile): Sw_Integer;
{$endif cdResource}
{ InitRezFile initializes a new PResourceFile using the name passed in
AFile and the stream mode passed in Mode and returns 0.
If an error occurs InitRezFile returns the DOS error and AResFile is
invalid. Possible DOS error values include:
2: file not found or other stream initialization error
11: invalid format - not a valid resource file }
{$ifdef cdResource}
function LoadResource (AFile: FNameStr): Boolean;
{$endif cdResource}
{ Load is used to open a resource file for use in the application.
For Load to return True, the resource file must be properly opened and
assigned to RezFile and the Hints string list must be successfully loaded
from the stream. If an error occurs, Load displays an English error
message using PrintStr and returns False. }
function MergeLists (Source, Dest: PMemStringList): Sw_Integer;
{ MergeLists moves all key/string pairs from Source to destination,
deleting them from Source. Duplicate strings are ignored. }
const
RMemStringList: TStreamRec = (
ObjType: idMemStringList;
VmtLink: Ofs(TypeOf(TMemStringList)^);
Load: @TMemStringList.Load;
Store: @TMemStringList.Store);
implementation
{****************************************************************************}
{ Private Declarations }
{****************************************************************************}
uses
{Memory, }Drivers;
{****************************************************************************}
{ TConstant object }
{****************************************************************************}
{****************************************************************************}
{ TConstant.Init }
{****************************************************************************}
constructor TConstant.Init (AValue: Word; AText: string);
begin
if not inherited Init then
Fail;
Value := AValue;
FText := NewStr(AText);
if (FText = nil) and (AText <> '') then
begin
inherited Done;
Fail;
end;
end;
{****************************************************************************}
{ TConstant.Done }
{****************************************************************************}
destructor TConstant.Done;
begin
DisposeStr(FText);
inherited Done;
end;
{****************************************************************************}
{ TConstant.SetText }
{****************************************************************************}
procedure TConstant.SetText (AText: string);
begin
DisposeStr(FText);
FText := NewStr(AText);
end;
{****************************************************************************}
{ TConstant.SetValue }
{****************************************************************************}
procedure TConstant.SetValue (AValue: string);
var
N: Word;
ErrorCode: Integer;
begin
Val(AValue,N,ErrorCode);
if ErrorCode = 0 then
Value := N;
end;
{****************************************************************************}
{ TConstant.Text }
{****************************************************************************}
function TConstant.Text: string;
begin
if (FText = nil) then
Text := ''
else Text := FText^;
end;
{****************************************************************************}
{ TConstant.ValueAsString }
{****************************************************************************}
function TConstant.ValueAsString: string;
var
S: string[5];
begin
Str(Value,S);
ValueAsString := S;
end;
{****************************************************************************}
{ TMemStringList Object }
{****************************************************************************}
{****************************************************************************}
{ TMemStringList.Init }
{****************************************************************************}
constructor TMemStringList.Init;
begin
if not inherited Init(10,10) then
Fail;
StringList := nil;
end;
{****************************************************************************}
{ TMemStringList.Load }
{****************************************************************************}
constructor TMemStringList.Load (var S: TStream);
begin
if not inherited Init(10,10) then
Fail;
StringList := New(PStringList,Load(S));
end;
{****************************************************************************}
{ TMemStringList.Done }
{****************************************************************************}
destructor TMemStringList.Done;
begin
if (StringList <> nil) then
Dispose(StringList,Done);
inherited Done;
end;
{****************************************************************************}
{ TMemStringList.Compare }
{****************************************************************************}
function TMemStringList.Compare (Key1, Key2: Pointer): Sw_Integer;
begin
if Word(Key1^) < Word(Key2^) then
Compare := -1
else Compare := Byte(Word(Key1^) > Word(Key2^));
end;
{****************************************************************************}
{ TMemStringList.Get }
{****************************************************************************}
function TMemStringList.Get (Key: Word): string;
var
i: Sw_Integer;
S: string;
begin
if (StringList = nil) then
begin { started with Init, use in memory string list }
if Search(@Key,i) then
Get := PConstant(At(i))^.Text
else Get := '';
end
else begin
S := StringList^.Get(Key);
Get := S;
end;
end;
{****************************************************************************}
{ TMemStringList.Insert }
{****************************************************************************}
procedure TMemStringList.Insert (Item: Pointer);
var
i: Sw_Integer;
begin
if (Item <> nil) then
begin
i := Count;
inherited Insert(Item);
if (i = Count) then { collection expansion failed }
Dispose(PConstant(Item),Done);
end;
end;
{****************************************************************************}
{ TMemStringList.KeyOf }
{****************************************************************************}
function TMemStringList.KeyOf (Item: Pointer): Pointer;
begin
KeyOf := @(PConstant(Item)^.Value);
end;
{****************************************************************************}
{ TMemStringList.LoadStrings }
{****************************************************************************}
function TMemStringList.LoadStrings: Sw_Integer;
procedure MakeEditableString (var Str: string);
const
SpecialChars: array[1..3] of Char = #3#10#13;
var
i, j: Byte;
begin
for i := 1 to 3 do
while (Pos(SpecialChars[i],Str) <> 0) do
begin
j := Pos(SpecialChars[i],Str);
System.Delete(Str,j,1);
case i of
1: System.Insert('#3',Str,j);
2: System.Insert('#10',Str,j);
3: System.Insert('#13',Str,j);
end;
end;
end;
var
Constant: PConstant;
i: Word;
S: string;
begin
LoadStrings := 0;
if (StringList = nil) then
begin
LoadStrings := 2;
Exit;
end;
for i := 0 to 65535 do
begin
S := StringList^.Get(i);
if (S <> '') then
begin
MakeEditableString(S);
Constant := NewConstant(i,S);
(*
if LowMemory then
begin
if (Constant <> nil) then
Dispose(Constant,Done);
LoadStrings := 8; { out of memory }
Exit;
end;
*)
Insert(Constant);
end;
end;
end;
{****************************************************************************}
{ TMemStringList.NewConstant }
{****************************************************************************}
function TMemStringList.NewConstant (Value: Word; S: string): PConstant;
begin
NewConstant := New(PConstant,Init(Value,S));
end;
{****************************************************************************}
{ TMemStringList.Put }
{****************************************************************************}
procedure TMemStringList.Put (Key: Word; S: string);
begin
Insert(New(PConstant,Init(Key,S)));
end;
{****************************************************************************}
{ TMemStringList.Store }
{****************************************************************************}
procedure TMemStringList.Store (var S: TStream);
var
StrList: PStrListMaker;
Size: Word;
procedure Total (Constant: PConstant);{$ifndef FPC}far;{$endif}
begin
with Constant^ do
Inc(Size,Succ(Length(Text)));
end;
procedure AddString (Constant: PConstant);{$ifndef FPC}far;{$endif}
const
Numbers = ['0'..'9'];
var
i, j: Byte;
N: Byte;
ErrorCode: Integer;
S: string;
begin
with Constant^ do
begin
{ convert formatting characters }
S := Text;
while (Pos('#',S) <> 0) do
begin
i := Succ(Pos('#',S));
j := i;
if (Length(S) > j) then
Inc(j,Byte(S[Succ(j)] in Numbers));
Val(Copy(S,i,j-i+1),N,ErrorCode);
System.Delete(S,Pred(i),j-i+2);
System.Insert(Char(N),S,Pred(i));
end;
StrList^.Put(Value,Text)
end;
end;
begin
Size := 0;
ForEach(@Total);
StrList := New(PStrListMaker,Init(Size,Count * 6));
if (StrList = nil) then
begin
S.Status := 8; { DOS error not enough memory }
Exit;
end;
ForEach(@AddString);
StrList^.Store(S);
Dispose(StrList,Done);
end;
{****************************************************************************}
{ Public Procedures and Functions }
{****************************************************************************}
{****************************************************************************}
{ Done }
{****************************************************************************}
procedure DoneResource;
begin
if (RezFile <> nil) then
begin
Dispose(RezFile,Done);
RezFile:=nil;
end;
if (Strings <> nil) then
begin
Dispose(Strings,Done);
Strings:=nil;
end;
if (Hints <> nil) then
begin
Dispose(Hints,Done);
Hints:=nil;
end;
if (Labels <> nil) then
begin
Dispose(Labels,Done);
Labels:=nil;
end;
end;
{****************************************************************************}
{ Init }
{****************************************************************************}
{$ifndef cdResource}
{$I strtxt.inc}
{ strtxt.inc contains the real strings and procedures InitRes... which
is converted from str.inc }
function InitResource: Boolean;
begin
InitResource := False;
Hints := New(PMemStringList,Init);
if (Hints = nil) then
begin
PrintStr('Fatal error. Could not create Hints list.');
Exit;
end;
Strings := New(PMemStringList,Init);
if (Strings = nil) then
begin
DoneResource;
Exit;
end;
Labels := New(PMemStringList,Init);
if (Labels = nil) then
begin
DoneResource;
Exit;
end;
{ now load the defaults }
InitResLabels;
InitResStrings;
InitResource := True;
end;
{$endif cdResource}
{****************************************************************************}
{ InitRezFile }
{****************************************************************************}
{$ifdef cdResource}
function InitRezFile (AFile: FNameStr; Mode: Word;
var AResFile: PResourceFile): Sw_Integer;
var
Stream: PBufStream;
Result: Sw_Integer;
begin
Stream := New(PBufStream,Init(AFile,Mode,RezBufferSize));
if (Stream = nil) then
Result := 2 { file not found; could also be out of memory }
else begin
AResFile := New(PResourceFile,Init(Stream));
if (AResFile = nil) then
begin
Dispose(Stream,Done);
Result := 11;
end
else Result := 0;
end;
InitRezFile := Result;
end;
{$endif cdResource}
{****************************************************************************}
{ Load }
{****************************************************************************}
{$ifdef cdResource}
function LoadResource (AFile: FNameStr): Boolean;
var
Stream: PBufStream;
begin
Load := False;
Stream := New(PBufStream,Init(AFile,stOpenRead,RezBufferSize));
if (Stream = nil) or (Stream^.Status <> 0) then
begin
Done;
PrintStr('Fatal error. Could not open resource file: ' + AFile);
Exit;
end;
RezFile := New(PResourceFile,Init(Stream));
if (RezFile = nil) then
begin
Dispose(Stream,Done);
Done;
PrintStr('Fatal error. Could not initialize resource file.');
Exit;
end;
Hints := PStringList(RezFile^.Get(reHints));
if (Hints = nil) then
begin
Done;
PrintStr('Fatal error. Could not load Hints string list.');
Exit;
end;
Strings := PStringList(RezFile^.Get(reStrings));
if (Strings = nil) then
begin
Done;
PrintStr('Fatal error. Could not load Strings string list.');
Exit;
end;
Load := True;
end;
{$endif cdResource}
{****************************************************************************}
{ MergeLists }
{****************************************************************************}
function MergeLists (Source, Dest: PMemStringList): Sw_Integer;
var
Result: Sw_Integer;
procedure MoveItem (Constant: PConstant);{$ifndef FPC}far;{$endif}
var
j: Sw_Integer;
begin
if (Result = 0) and (not Dest^.Search(Dest^.KeyOf(Constant),j)) then
begin
j := Dest^.Count;
Dest^.Insert(Constant);
if (j = Dest^.Count) then
Result := 8
else Source^.Delete(Constant);
end;
end;
begin
if (Source = nil) or (Dest = nil) then
begin
MergeLists := 6;
Exit;
end;
Result := 0;
Source^.ForEach(@MoveItem);
MergeLists := Result;
end;
{****************************************************************************}
{ Unit Initialization }
{****************************************************************************}
begin
RezFile := nil;
Hints := nil;
Strings := nil;
Labels := nil;
end.
|