2
$Id: mkxmlrpc.pp,v 1.5 2004/02/02 16:53:07 sg Exp $
4
Automatic XML-RPC wrapper generator
6
Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org
8
See the file COPYING.FPC, included in this distribution,
9
for details about the copyright.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
uses SysUtils, Classes, PParser, PasTree, PasWrite;
21
SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
22
SNoServerClassNameProvided =
23
'No server class name provided (use --serverclass=<name>)';
25
'No name for generated unit provided (use --unitname=<name>)';
28
TParserEngine = class(TPasTreeContainer)
30
Modules, UsedModules: TList;
31
CurModule: TPasModule;
34
destructor Destroy; override;
35
function CreateElement(AClass: TPTreeElement; const AName: String;
36
AParent: TPasElement; AVisibility: TPasMemberVisibility;
37
const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
39
function FindElement(const AName: String): TPasElement; override;
40
function FindModule(const AName: String): TPasModule; override;
44
Element: TPasClassType;
50
destructor Destroy; override;
51
procedure AddServerClass(const AClassName: String);
53
UsedModules: TStringList;
57
Engine: TParserEngine;
60
constructor TParserEngine.Create;
63
Modules := TList.Create;
64
UsedModules := TList.Create;
67
destructor TParserEngine.Destroy;
74
function TParserEngine.CreateElement(AClass: TPTreeElement; const AName: String;
75
AParent: TPasElement; AVisibility: TPasMemberVisibility;
76
const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
78
Result := AClass.Create(AName, AParent);
79
Result.Visibility := AVisibility;
80
if AClass.InheritsFrom(TPasModule) then
83
CurModule := TPasModule(Result);
87
function TParserEngine.FindElement(const AName: String): TPasElement;
89
function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement;
95
l := AModule.InterfaceSection.Declarations;
96
for i := 0 to l.Count - 1 do
98
Result := TPasElement(l[i]);
99
if CompareText(Result.Name, LocalName) = 0 then
102
for j := 0 to UsedModules.Count - 1 do
103
if CompareText(TPasModule(UsedModules[j]).Name, AModule.Name) = 0 then
109
UsedModules.Add(AModule);
118
//ModuleName, LocalName: String;
121
{!!!: Don't know if we ever will have to use the following:
122
i := Pos('.', AName);
125
WriteLn('Dot found in name: ', AName);
129
Result := FindInModule(CurModule, AName);
130
if not Assigned(Result) then
131
for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
133
Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
134
if Module.ClassType = TPasModule then
136
Result := FindInModule(TPasModule(Module), AName);
137
if Assigned(Result) then
144
function TParserEngine.FindModule(const AName: String): TPasModule;
148
for i := Modules.Count - 1 downto 0 do
150
Result := TPasModule(Modules[i]);
151
if CompareText(Result.Name, AName) = 0 then
158
constructor TRPCList.Create;
160
ServerClasses := TList.Create;
161
UsedModules := TStringList.Create;
164
destructor TRPCList.Destroy;
169
for i := 0 to ServerClasses.Count - 1 do
170
TServerClass(ServerClasses[i]).Free;
174
procedure TRPCList.AddServerClass(const AClassName: String);
176
Element: TPasClassType;
177
ServerClass: TServerClass;
179
Element := TPasClassType(Engine.FindElement(AClassName));
180
if not Assigned(Element) then
182
WriteLn(StdErr, 'Server class "', AClassName, '" not found!');
185
if (not Element.InheritsFrom(TPasClassType)) or
186
(Element.ObjKind <> okClass) then
188
WriteLn('"', AClassName, '" is not a class!');
191
ServerClass := TServerClass.Create;
192
ServerClasses.Add(ServerClass);
193
ServerClass.Element := Element;
194
ServerClass.ImplName := Copy(Element.Name, 2, Length(Element.Name));
195
UsedModules.Add(Element.GetModule.Name);
200
OutputFilename, UnitName: String;
203
procedure WriteClassServerSource(ServerClass: TPasClassType;
204
ImplementationSection: TPasSection; Method, ProcImpl: TPasProcedureImpl;
205
const MethodPrefix: String; NestingLevel: Integer);
207
{ Method: Main server method
208
ProcImpl: Current procedure (may be identical with Method) }
211
TConversionInfo = record
212
ConverterName, TypecastFunction: String;
213
ArgIsParent: Boolean;
216
function MakeStructConverter(AClass: TPasClassType;
217
Referrer: TPasProcedureImpl): TPasProcedureImpl; forward;
219
function MakeArrayConverter(Member, ArraySizeProp: TPasProperty;
220
ProcessProc, Referrer: TPasProcedureImpl): TPasProcedureImpl; forward;
222
function FindArraySizeProperty(AArrayProp: TPasProperty): TPasProperty;
227
Name := Copy(AArrayProp.Name, 1, Length(AArrayProp.Name) - 1) + 'Count';
228
for i := 0 to TPasClassType(AArrayProp.Parent).Members.Count - 1 do
230
Result := TPasProperty(TPasClassType(AArrayProp.Parent).Members[i]);
231
if (Result.ClassType = TPasProperty) and (Result.Visibility = visPublic)
232
and (CompareStr(Result.Name, Name) = 0) then
236
Name := AArrayProp.Name + 'Count';
237
for i := 0 to TPasClassType(AArrayProp.Parent).Members.Count - 1 do
239
Result := TPasProperty(TPasClassType(AArrayProp.Parent).Members[i]);
240
if (Result.ClassType = TPasProperty) and (Result.Visibility = visPublic)
241
and (CompareStr(Result.Name, Name) = 0) then
247
function GetConversionInfo(Element: TPasElement;
248
Referrer: TPasProcedureImpl): TConversionInfo;
251
ArraySizeProp: TPasProperty;
253
FillChar(Result, SizeOf(Result), 0);
254
Result.ArgIsParent := False;
256
if Element.ClassType = TPasProperty then
258
ArraySizeProp := FindArraySizeProperty(TPasProperty(Element));
259
if Assigned(ArraySizeProp) then
261
Result.ConverterName := MakeArrayConverter(TPasProperty(Element),
262
ArraySizeProp, ProcImpl, Referrer).Name;
263
Result.ArgIsParent := True;
266
Element := TPasProperty(Element).VarType;
269
if Element.ClassType = TPasUnresolvedTypeRef then
271
s := UpperCase(Element.Name);
272
if (s = 'BYTE') or (s = 'SHORTINT') or (S = 'SMALLINT') or
273
(s = 'INTEGER') or (s = 'LONGINT') or (s = 'CARDINAL') or
274
(s = 'INT64') or (s = 'QUADWORD') then
275
Result.ConverterName := 'AWriter.CreateIntValue'
276
else if (s = 'BOOLEAN') or (s = 'WORDBOOL') or (s = 'LONGBOOL') then
277
Result.ConverterName := 'AWriter.CreateBooleanValue'
278
else if s = 'STRING' then
279
Result.ConverterName := 'AWriter.CreateStringValue'
280
else if (s = 'FLOAT') or (s = 'SINGLE') or (s = 'DOUBLE') or
281
(s = 'EXTENDED') then
282
Result.ConverterName := 'AWriter.CreateDoubleValue'
283
else if s = 'TDATETIME' then
284
Result.ConverterName := 'AWriter.CreateDateTimeValue';
285
end else if Element.ClassType = TPasClassType then
286
Result.ConverterName := MakeStructConverter(TPasClassType(Element), Referrer).Name
287
else if Element.ClassType = TPasEnumType then
289
Result.ConverterName := 'AWriter.CreateIntValue';
290
Result.TypecastFunction := 'Ord';
293
if Length(Result.ConverterName) = 0 then
294
raise Exception.Create('Result type not supported: ' + Element.ClassName +
298
function MakeAccessor(ConversionInfo: TConversionInfo;
299
const DataSource, ArrayIndex: String): String;
301
Result := ConversionInfo.ConverterName + '(';
302
if ConversionInfo.TypecastFunction <> '' then
303
Result := Result + ConversionInfo.TypecastFunction + '(';
304
Result := Result + DataSource;
305
if ConversionInfo.TypecastFunction <> '' then
306
Result := Result + ')';
307
if ArrayIndex <> '' then
308
Result := Result + '[' + ArrayIndex + ']';
309
Result := Result + ')';
312
function GetParseValueFnName(PasType: TPasType): String;
316
SetLength(Result, 0);
317
if PasType.ClassType = TPasArgument then
319
if TPasArgument(PasType).Access = argVar then
320
raise Exception.Create('"var" arguments are not allowed');
321
PasType := TPasArgument(PasType).ArgType;
324
if PasType.ClassType = TPasUnresolvedTypeRef then
326
s := UpperCase(PasType.Name);
327
if (s = 'BYTE') or (s = 'SHORTINT') or (S = 'SMALLINT') or
328
(s = 'INTEGER') or (s = 'LONGINT') or (s = 'CARDINAL') or
329
(s = 'INT64') or (s = 'QUADWORD') then
331
else if (s = 'BOOLEAN') or (s = 'WORDBOOL') or (s = 'LONGBOOL') then
333
else if s = 'STRING' then
335
else if (s = 'FLOAT') or (s = 'SINGLE') or (s = 'DOUBLE') or
336
(s = 'EXTENDED') then
338
else if s = 'TDATETIME' then
339
Result := 'DateTime';
341
if Length(Result) = 0 then
342
raise Exception.Create('Argument type not supported: ' +
343
PasType.ClassName + ' ' + PasType.Name);
346
function NeedLocalProc(const ProcName: String;
347
Referrer: TPasProcedureImpl): TPasProcedureImpl;
351
for i := 0 to Method.Locals.Count - 1 do
353
Result := TPasProcedureImpl(Method.Locals[i]);
354
if Result.Name = ProcName then
356
j := Method.Locals.IndexOf(Referrer);
357
if (j >= 0) and (i >= j) then
359
// Move existing converter to the top and exit
360
Method.Locals.Delete(i);
361
j := Method.Locals.IndexOf(ProcImpl);
364
Method.Locals.Insert(j, Result);
372
function MakeStructConverter(AClass: TPasClassType;
373
Referrer: TPasProcedureImpl): TPasProcedureImpl;
375
ConverterName, s: String;
376
Commands: TPasImplCommands;
378
LocalMember: TPasElement;
379
ConversionInfo: TConversionInfo;
381
ConverterName := 'Convert' + AClass.Name;
382
Result := NeedLocalProc(ConverterName, Referrer);
383
if Assigned(Result) then
386
Result := TPasProcedureImpl.Create(ConverterName, Method);
387
i := Method.Locals.IndexOf(Referrer);
390
Method.Locals.Insert(i, Result);
391
Result.ProcType := TPasFunctionType.Create('', Result);
392
Result.ProcType.CreateArgument('Inst', AClass.Name);
393
TPasFunctionType(Result.ProcType).ResultEl :=
394
TPasResultElement.Create('', Result);
395
TPasFunctionType(Result.ProcType).ResultEl.ResultType :=
396
TPasUnresolvedTypeRef.Create('TXMLRPCStruct', Result);
398
Result.Body := TPasImplBlock.Create('', Result);
399
Commands := Result.Body.AddCommands;
400
Commands.Commands.Add('Result := AWriter.CreateStruct');
401
for i := 0 to AClass.Members.Count - 1 do
403
LocalMember := TPasElement(AClass.Members[i]);
404
if LocalMember.ClassType = TPasProperty then
406
ConversionInfo := GetConversionInfo(LocalMember, Result);
407
if ConversionInfo.ArgIsParent then
410
s := 'Inst.' + LocalMember.Name;
411
s := 'AWriter.AddStructMember(Result, ''' + LocalMember.Name + ''', ' +
412
MakeAccessor(ConversionInfo, s, '') + ')';
413
Commands.Commands.Add(s);
418
function MakeArrayConverter(Member, ArraySizeProp: TPasProperty;
419
ProcessProc, Referrer: TPasProcedureImpl): TPasProcedureImpl;
422
ConverterName, s: String;
423
Commands: TPasImplCommands;
424
VarMember: TPasVariable;
425
ForLoop: TPasImplForLoop;
426
ConversionInfo: TConversionInfo;
428
ConverterName := 'Convert' + Member.Parent.Name + '_' + Member.Name;
429
Result := NeedLocalProc(ConverterName, Referrer);
430
if Assigned(Result) then
433
Result := TPasProcedureImpl.Create(ConverterName, Method);
434
i := Method.Locals.IndexOf(Referrer);
437
Method.Locals.Insert(i, Result);
438
Result.ProcType := TPasFunctionType.Create('', Result);
439
Result.ProcType.CreateArgument('Inst', Member.Parent.Name);
440
TPasFunctionType(Result.ProcType).ResultEl :=
441
TPasResultElement.Create('', Result);
442
TPasFunctionType(Result.ProcType).ResultEl.ResultType :=
443
TPasUnresolvedTypeRef.Create('TXMLRPCArray', Result);
445
Result.Body := TPasImplBlock.Create('', Result);
446
Commands := Result.Body.AddCommands;
447
Commands.Commands.Add('Result := AWriter.CreateArray');
449
VarMember := TPasVariable.Create('i', Result);
450
Result.Locals.Add(VarMember);
451
VarMember.VarType := TPasUnresolvedTypeRef.Create('Integer', VarMember);
453
ForLoop := Result.Body.AddForLoop(TPasVariable.Create('i', Result),
454
'0', MethodPrefix + ArraySizeProp.Name + ' - 1');
455
ForLoop.Body := TPasImplCommand.Create('', ForLoop);
456
ConversionInfo := GetConversionInfo(Member.VarType, Result);
457
if ConversionInfo.ArgIsParent then
460
s := 'Inst.' + Member.Name + '[i]';
461
s := 'AWriter.AddArrayElement(Result, ' +
462
MakeAccessor(ConversionInfo, s, '') + ')';
463
TPasImplCommand(ForLoop.Body).Command := s;
466
function CreateDispatcher(VarType: TPasClassType;
467
Referrer: TPasProcedureImpl): TPasProcedureImpl;
469
DispatcherName: String;
471
DispatcherName := 'Dispatch' + VarType.Name;
472
Result := NeedLocalProc(DispatcherName, Referrer);
473
if Assigned(Result) then
476
// Create new dispatcher method
477
Result := TPasProcedureImpl.Create(DispatcherName, Method);
478
if ProcImpl = Method then
479
Method.Locals.Insert(0, Result)
481
Method.Locals.Insert(Method.Locals.IndexOf(Referrer), Result);
482
Result.ProcType := TPasProcedureType.Create('', Result);
483
Result.ProcType.CreateArgument('Inst', VarType.Name);
484
Result.ProcType.CreateArgument('Level', 'Integer');
485
WriteClassServerSource(VarType,
486
ImplementationSection, Method, Result, 'Inst.', NestingLevel + 1);
491
IfElse, ParentIfElse: TPasImplIfElse;
493
procedure CreateBranch(const MethodName: String);
495
if Assigned(ParentIfElse) then
497
IfElse := TPasImplIfElse.Create('', ParentIfElse);
498
ParentIfElse.ElseBranch := IfElse;
501
IfElse := TPasImplIfElse.Create('', ProcImpl.Body);
502
ProcImpl.Body.Elements.Add(IfElse);
504
ParentIfElse := IfElse;
505
IfElse.Condition := 's = ''' + UpperCase(MethodName) + '''';
508
procedure ProcessMethodCall(Member: TPasProcedure);
510
function MakeProcArgs(Args: TList): String;
514
if (not Assigned(Args)) or (Args.Count = 0) then
519
for i := 0 to Args.Count - 1 do
522
Result := Result + ', ';
523
Result := Result + 'AParser.GetPrev' + GetParseValueFnName(TPasType(Args[i]));
525
Result := Result + ')';
530
Commands: TPasImplCommands;
533
CreateBranch(Member.Name);
534
Commands := TPasImplCommands.Create('', IfElse);
535
IfElse.IfBranch := Commands;
537
if TPasProcedure(Member).ProcType.Args.Count > 0 then
538
Commands.Commands.Add('AParser.ResetValueCursor');
539
if Member.ClassType = TPasProcedure then
541
Commands.Commands.Add(MethodPrefix + Member.Name +
542
MakeProcArgs(TPasProcedure(Member).ProcType.Args));
543
Commands.Commands.Add('AWriter.WriteResponse(nil)');
547
s := MethodPrefix + Member.Name +
548
MakeProcArgs(TPasProcedure(Member).ProcType.Args);
549
Commands.Commands.Add('AWriter.WriteResponse(' +
550
MakeAccessor(GetConversionInfo(TPasFunctionType(TPasFunction(Member).
551
ProcType).ResultEl.ResultType, ProcImpl), s, '') + ')');
555
procedure ProcessProperty(Member: TPasProperty);
557
LocalIfElse: TPasImplIfElse;
558
IsArray, IsStruct: Boolean;
560
Commands: TPasImplCommands;
561
Command: TPasImplCommand;
562
ConversionInfo: TConversionInfo;
564
if Member.ReadAccessorName <> '' then
566
CreateBranch('Get' + Member.Name);
568
IsArray := (Member.Args.Count = 1) and
569
Assigned(FindArraySizeProperty(Member));
570
IsStruct := Member.VarType.ClassType = TPasClassType;
573
s := CreateDispatcher(TPasClassType(Member.VarType), ProcImpl).Name +
574
'(' + MethodPrefix + Member.Name;
576
if NestingLevel = 0 then
581
if IsArray or (IsStruct and (Member.Args.Count = 0)) then
583
LocalIfElse := TPasImplIfElse.Create('', IfElse);
584
IfElse.IfBranch := LocalIfElse;
585
LocalIfElse.Condition := 'APath.Count <= ' + s2;
591
LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
592
TPasImplCommand(LocalIfElse.IfBranch).Command :=
593
'AWriter.WriteResponse(' +
594
MakeAccessor(GetConversionInfo(Member, ProcImpl),
595
Copy(MethodPrefix, 1, Length(MethodPrefix) - 1), '') + ')';
597
LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
598
TPasImplCommand(LocalIfElse.ElseBranch).Command :=
599
s + '[AParser.GetNext' +
600
GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType) + '], ' +
604
if Member.Args.Count = 0 then
606
LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
607
TPasImplCommand(LocalIfElse.IfBranch).Command :=
608
'AWriter.WriteResponse(' +
609
MakeAccessor(GetConversionInfo(Member, ProcImpl),
610
MethodPrefix + Member.Name, '') + ')';
611
LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
612
TPasImplCommand(LocalIfElse.ElseBranch).Command := s + ', ' + s2 + ')';
615
IfElse.IfBranch := TPasImplCommand.Create('', IfElse);
616
TPasImplCommand(IfElse.IfBranch).Command := s + '[AParser.GetNext' +
617
GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType) + '], ' +
623
LocalIfElse.IfBranch := TPasImplCommand.Create('', LocalIfElse);
624
TPasImplCommand(LocalIfElse.IfBranch).Command :=
625
'AWriter.WriteResponse(' +
626
MakeAccessor(GetConversionInfo(Member, ProcImpl),
627
Copy(MethodPrefix, 1, Length(MethodPrefix) - 1), '') + ')';
629
LocalIfElse.ElseBranch := TPasImplCommand.Create('', LocalIfElse);
630
TPasImplCommand(LocalIfElse.ElseBranch).Command :=
631
'AWriter.WriteResponse(' +
632
MakeAccessor(GetConversionInfo(Member.VarType, ProcImpl),
633
MethodPrefix + Member.Name, 'AParser.GetNext' +
634
GetParseValueFnName(TPasArgument(Member.Args[0]).ArgType)) + ')';
637
IfElse.IfBranch := TPasImplCommand.Create('', IfElse);
638
TPasImplCommand(IfElse.IfBranch).Command := 'AWriter.WriteResponse(' +
639
MakeAccessor(GetConversionInfo(Member.VarType, ProcImpl),
640
MethodPrefix + Member.Name, '') + ')';
644
if Member.WriteAccessorName <> '' then
646
CreateBranch('Set' + Member.Name);
647
Commands := TPasImplCommands.Create('', IfElse);
648
IfElse.IfBranch := Commands;
649
Commands.Commands.Add('// Not supported by mkxmlrpc yet');
654
VarMember: TPasVariable;
656
Command: TPasImplCommand;
659
VarMember := TPasVariable.Create('s', ProcImpl);
660
ProcImpl.Locals.Add(VarMember);
661
VarMember.VarType := TPasUnresolvedTypeRef.Create('String', VarMember);
662
ProcImpl.Body := TPasImplBlock.Create('', ProcImpl);
663
if NestingLevel = 0 then
664
ProcImpl.Body.AddCommand('s := APath[' + IntToStr(NestingLevel) + ']')
666
ProcImpl.Body.AddCommand('s := APath[Level]');
668
for i := 0 to ServerClass.Members.Count - 1 do
670
Member := TPasElement(ServerClass.Members[i]);
671
if Member.Visibility <> visPublic then
674
if (Member.ClassType = TPasProcedure) or (Member.ClassType = TPasFunction)
676
ProcessMethodCall(TPasProcedure(Member))
677
else if Member.ClassType = TPasProperty then
678
ProcessProperty(TPasProperty(Member))
679
else if (Member.ClassType <> TPasConstructor) and
680
(Member.ClassType <> TPasDestructor) then
681
WriteLn('Warning: Unsupportet member type: ', Member.ElementTypeName);
684
if Assigned(ParentIfElse) then
686
Command := TPasImplCommand.Create('', ParentIfElse);
687
ParentIfElse.ElseBranch := Command;
690
Command := TPasImplCommand.Create('', ProcImpl.Body);
691
ProcImpl.Body.Elements.Add(Command);
693
Command.Command := 'AWriter.WriteFaultResponse(2, ''Invalid method name'')';
696
procedure WriteFPCServerSource;
700
InterfaceSection, ImplementationSection: TPasSection;
701
VarMember: TPasVariable;
702
PropertyMember: TPasProperty;
703
ProcMember: TPasProcedure;
705
ServerClass: TPasClassType;
707
ProcImpl: TPasProcedureImpl;
710
Module := TPasModule.Create(UnitName, nil);
712
InterfaceSection := TPasSection.Create('', Module);
713
Module.InterfaceSection := InterfaceSection;
714
ImplementationSection := TPasSection.Create('', Module);
715
Module.ImplementationSection := ImplementationSection;
716
InterfaceSection.AddUnitToUsesList('Classes');
717
InterfaceSection.AddUnitToUsesList('XMLRPC');
718
for i := 0 to RPCList.UsedModules.Count - 1 do
719
InterfaceSection.AddUnitToUsesList(RPCList.UsedModules[i]);
721
for i := 0 to RPCList.ServerClasses.Count - 1 do
722
with TServerClass(RPCList.ServerClasses[i]) do
724
ServerClass := TPasClassType.Create('T' + ImplName + 'XMLRPCServlet',
726
InterfaceSection.Declarations.Add(ServerClass);
727
ServerClass.ObjKind := okClass;
728
ServerClass.AncestorType :=
729
TPasUnresolvedTypeRef.Create('TXMLRPCServlet', ServerClass);
731
// Create private field which holds the implementation instance
732
VarMember := TPasVariable.Create('F' + ImplName, ServerClass);
733
VarMember.Visibility := visPrivate;
734
VarMember.VarType := TPasUnresolvedTypeRef.Create(Element.Name, VarMember);
735
ServerClass.Members.Add(VarMember);
737
// Create dispatcher method
738
ProcMember := TPasProcedure.Create('Dispatch', ServerClass);
739
ProcMember.Visibility := visProtected;
740
ProcMember.IsOverride := True;
741
ProcMember.ProcType := TPasProcedureType.Create('', ProcMember);
742
ProcMember.ProcType.CreateArgument('AParser', 'TXMLRPCParser').
743
Visibility := visPublic;
744
ProcMember.ProcType.CreateArgument('AWriter', 'TXMLRPCWriter').
745
Visibility := visPublic;
746
ProcMember.ProcType.CreateArgument('APath', 'TStrings').
747
Visibility := visPublic;
748
ServerClass.Members.Add(ProcMember);
750
// Create published property for implementation instance
751
PropertyMember := TPasProperty.Create(ImplName, ServerClass);
752
PropertyMember.Visibility := visPublished;
753
PropertyMember.VarType := VarMember.VarType;
754
VarMember.VarType.AddRef;
755
PropertyMember.ReadAccessorName := 'F' + ImplName;
756
PropertyMember.WriteAccessorName := 'F' + ImplName;
757
ServerClass.Members.Add(PropertyMember);
759
// Create dispatcher implementation
760
ProcImpl := TPasProcedureImpl.Create('Dispatch', ServerClass);
761
ImplementationSection.Declarations.Add(ProcImpl);
762
ProcImpl.ProcType := ProcMember.ProcType;
763
ProcMember.ProcType.AddRef;
764
ProcImpl.ProcType.AddRef;
765
WriteClassServerSource(Element, ImplementationSection, ProcImpl,
766
ProcImpl, ImplName + '.', 0);
769
for i := 0 to Engine.UsedModules.Count - 1 do
772
for j := 0 to RPCList.UsedModules.Count - 1 do
773
if CompareText(RPCList.UsedModules[j],
774
TPasModule(Engine.UsedModules[i]).Name) = 0 then
780
ImplementationSection.AddUnitToUsesList(
781
TPasModule(Engine.UsedModules[i]).Name);
784
Stream := THandleStream.Create(StdOutputHandle);
786
WritePasFile(Module, Stream);
791
Stream := TFileStream.Create(OutputFilename, fmCreate);
793
WritePasFile(Module, Stream);
806
InputFiles, ClassList: TStringList;
808
InputFiles := TStringList.Create;
809
ClassList := TStringList.Create;
811
for i := 1 to ParamCount do
817
Cmd := Copy(s, 1, j - 1);
818
Arg := Copy(s, j + 1, Length(s));
824
if (Cmd = '-i') or (Cmd = '--input') then
826
else if Cmd = '--output' then
827
OutputFilename := Arg
828
else if Cmd = '--unitname' then
830
else if Cmd = '--serverclass' then
833
WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
836
if ClassList.Count = 0 then
838
WriteLn(StdErr, SNoServerClassNameProvided);
842
if UnitName = '' then
844
WriteLn(StdErr, SNoUnitNameProvided);
848
Engine := TParserEngine.Create;
850
// Engine.SetPackageName('XMLRPC');
851
for i := 0 to InputFiles.Count - 1 do
852
ParseSource(Engine, InputFiles[i], '', '');
854
RPCList := TRPCList.Create;
856
for i := 0 to ClassList.Count - 1 do
857
RPCList.AddServerClass(ClassList[i]);
858
WriteFPCServerSource;
873
$Log: mkxmlrpc.pp,v $
874
Revision 1.5 2004/02/02 16:53:07 sg
875
* Small fix in GetConversionInfo (result was not fully cleared)
877
Revision 1.4 2003/11/22 12:08:32 sg
878
* Better error reporting with line numbers
879
* Array properties: The size property now can just match the name of the
880
array property as well; so it now also works without a plural "s" after
882
* Added support for TDateTime parameters and results
884
Revision 1.3 2003/06/25 08:56:26 sg
885
* Added support for reading set properties
887
Revision 1.2 2003/06/12 19:00:53 michael
888
* Supports usage of declarations from other units (as long as mkxmlrpc
889
parsed these units due to a --input=unitname command)
891
Revision 1.1 2003/04/26 16:42:10 sg