fpdocxmlopts.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. unit fpdocxmlopts;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpdocproj, dom, fptemplate;
  6. Type
  7. { TXMLFPDocOptions }
  8. TXMLFPDocOptions = Class(TComponent)
  9. private
  10. FExpandMacros: Boolean;
  11. FMacros: TStrings;
  12. procedure SetMacros(AValue: TStrings);
  13. Protected
  14. Procedure Error(Const Msg : String);
  15. Procedure Error(Const Fmt : String; Args : Array of Const);
  16. Procedure LoadPackage(APackage : TFPDocPackage; E : TDOMElement); virtual;
  17. Procedure LoadPackages(Packages : TFPDocPackages; E : TDOMElement);
  18. Procedure LoadEngineOptions(Options : TEngineOptions; E : TDOMElement); virtual;
  19. Procedure SaveEngineOptions(Options : TEngineOptions; XML : TXMLDocument; AParent : TDOMElement); virtual;
  20. procedure SaveDescription(const ADescription: String; XML: TXMLDocument; AParent: TDOMElement); virtual;
  21. procedure SaveInputFile(const AInputFile: String; XML: TXMLDocument; AParent: TDOMElement);virtual;
  22. Procedure SavePackage(APackage : TFPDocPackage; XML : TXMLDocument; AParent : TDOMElement); virtual;
  23. procedure DoMacro(Sender: TObject; const TagString: String; TagParams: TStringList; out ReplaceText: String); virtual;
  24. function ExpandMacrosInFile(AFileName: String): TStream; virtual;
  25. Public
  26. Constructor Create (AOwner : TComponent); override;
  27. Destructor Destroy; override;
  28. Procedure LoadOptionsFromFile(AProject : TFPDocProject; Const AFileName : String);
  29. Procedure LoadFromXML(AProject : TFPDocProject; XML : TXMLDocument); virtual;
  30. Procedure SaveOptionsToFile(AProject : TFPDocProject; Const AFileName : String);
  31. procedure SaveToXML(AProject : TFPDocProject; ADoc: TXMLDocument); virtual;
  32. Property Macros : TStrings Read FMacros Write SetMacros;
  33. Property ExpandMacros : Boolean Read FExpandMacros Write FExpandMacros;
  34. end;
  35. EXMLFPdoc = Class(Exception);
  36. Function IndexOfString(S : String; List : Array of string) : Integer;
  37. Const
  38. OptionCount = 11;
  39. OptionNames : Array[0..OptionCount] of string
  40. = ('hide-protected','warn-no-node','show-private',
  41. 'stop-on-parser-error', 'ostarget','cputarget',
  42. 'mo-dir','parse-impl','format', 'language',
  43. 'package','dont-trim');
  44. implementation
  45. Uses XMLRead, XMLWrite;
  46. Resourcestring
  47. SErrInvalidRootNode = 'Invalid options root node: Got "%s", expected "docproject"';
  48. SErrNoPackagesNode = 'No "packages" node found in docproject';
  49. SErrNoInputFile = 'unit tag without file attribute found';
  50. SErrNoDescrFile = 'description tag without file attribute';
  51. { TXMLFPDocOptions }
  52. Function IndexOfString(S : String; List : Array of string) : Integer;
  53. begin
  54. S:=UpperCase(S);
  55. Result:=High(List);
  56. While (Result>=0) and (S<>UpperCase(List[Result])) do
  57. Dec(Result);
  58. end;
  59. procedure TXMLFPDocOptions.SetMacros(AValue: TStrings);
  60. begin
  61. if FMacros=AValue then Exit;
  62. FMacros.Assign(AValue);
  63. end;
  64. procedure TXMLFPDocOptions.Error(Const Msg: String);
  65. begin
  66. Raise EXMLFPDoc.Create(Msg);
  67. end;
  68. procedure TXMLFPDocOptions.Error(const Fmt: String; Args: array of const);
  69. begin
  70. Raise EXMLFPDoc.CreateFmt(Fmt,Args);
  71. end;
  72. procedure TXMLFPDocOptions.LoadPackage(APackage: TFPDocPackage; E: TDOMElement);
  73. Function LoadInput(I : TDOMElement) : String;
  74. Var
  75. S : String;
  76. begin
  77. Result:=I['file'];
  78. If (Result='') then
  79. Error(SErrNoInputFile);
  80. S:=I['options'];
  81. if (S<>'') then
  82. Result:=S+' '+Result;
  83. end;
  84. Function LoadDescription(I : TDOMElement) : String;
  85. begin
  86. Result:=I['file'];
  87. If (Result='') then
  88. Error(SErrNoDescrFile);
  89. end;
  90. Var
  91. N,S : TDOMNode;
  92. O : TDomElement;
  93. begin
  94. APackage.Name:=E['name'];
  95. APackage.output:=E['output'];
  96. APackage.ContentFile:=E['content'];
  97. N:=E.FirstChild;
  98. While (N<>Nil) do
  99. begin
  100. If (N.NodeType=ELEMENT_NODE) then
  101. begin
  102. O:=N as TDOMElement;
  103. If (O.NodeName='units') then
  104. begin
  105. S:=O.FirstChild;
  106. While (S<>Nil) do
  107. begin
  108. If (S.NodeType=Element_Node) and (S.NodeName='unit') then
  109. APackage.Inputs.add(LoadInput(S as TDomElement));
  110. S:=S.NextSibling;
  111. end;
  112. end
  113. else If (O.NodeName='descriptions') then
  114. begin
  115. S:=O.FirstChild;
  116. While (S<>Nil) do
  117. begin
  118. If (S.NodeType=Element_Node) and (S.NodeName='description') then
  119. APackage.Descriptions.add(LoadDescription(S as TDomElement));
  120. S:=S.NextSibling;
  121. end;
  122. end
  123. end;
  124. N:=N.NextSibling;
  125. end;
  126. end;
  127. procedure TXMLFPDocOptions.LoadPackages(Packages: TFPDocPackages; E: TDOMElement
  128. );
  129. Var
  130. N : TDOMNode;
  131. begin
  132. N:=E.FirstChild;
  133. While (N<>Nil) do
  134. begin
  135. If (N.NodeName='package') and (N.NodeType=ELEMENT_NODE) then
  136. LoadPackage(Packages.Add as TFPDocPackage, N as TDOMElement);
  137. N:=N.NextSibling;
  138. end;
  139. end;
  140. procedure TXMLFPDocOptions.LoadEngineOptions(Options: TEngineOptions;
  141. E: TDOMElement);
  142. Function TrueValue(V : String) : Boolean;
  143. begin
  144. V:=LowerCase(V);
  145. Result:=(v='true') or (v='1') or (v='yes');
  146. end;
  147. Var
  148. O : TDOMnode;
  149. N,V : String;
  150. begin
  151. O:=E.FirstChild;
  152. While (O<>Nil) do
  153. begin
  154. If (O.NodeType=Element_NODE) and (O.NodeName='option') then
  155. begin
  156. N:=LowerCase(TDOMElement(o)['name']);
  157. V:=TDOMElement(o)['value'];
  158. Case IndexOfString(N,OptionNames) of
  159. 0 : Options.HideProtected:=TrueValue(v);
  160. 1 : Options.WarnNoNode:=TrueValue(v);
  161. 2 : Options.ShowPrivate:=TrueValue(v);
  162. 3 : Options.StopOnParseError:=TrueValue(v);
  163. 4 : Options.ostarget:=v;
  164. 5 : Options.cputarget:=v;
  165. 6 : Options.MoDir:=V;
  166. 7 : Options.InterfaceOnly:=Not TrueValue(V);
  167. 8 : Options.Backend:=V;
  168. 9 : Options.Language:=v;
  169. 10 : Options.DefaultPackageName:=V;
  170. 11 : Options.DontTrim:=TrueValue(V);
  171. else
  172. Options.BackendOptions.add('--'+n);
  173. Options.BackendOptions.add(v);
  174. end;
  175. end;
  176. O:=O.NextSibling
  177. end;
  178. end;
  179. procedure TXMLFPDocOptions.SaveToXML(AProject: TFPDocProject; ADoc: TXMLDocument);
  180. var
  181. i: integer;
  182. E,PE: TDOMElement;
  183. begin
  184. E:=ADoc.CreateElement('docproject');
  185. ADoc.AppendChild(E);
  186. E:=ADoc.CreateElement('options');
  187. ADoc.DocumentElement.AppendChild(E);
  188. SaveEngineOptions(AProject.Options,ADoc,E);
  189. E:=ADoc.CreateElement('packages');
  190. ADoc.DocumentElement.AppendChild(E);
  191. for i := 0 to AProject.Packages.Count - 1 do
  192. begin
  193. PE:=ADoc.CreateElement('package');
  194. E.AppendChild(PE);
  195. SavePackage(AProject.Packages[i],ADoc,PE);
  196. end;
  197. end;
  198. Procedure TXMLFPDocOptions.SaveEngineOptions(Options : TEngineOptions; XML : TXMLDocument; AParent : TDOMElement);
  199. procedure AddStr(const n, v: string);
  200. var
  201. E : TDOMElement;
  202. begin
  203. if (v='') then
  204. Exit;
  205. E:=XML.CreateElement('option');
  206. AParent.AppendChild(E);
  207. E['name'] := n;
  208. E['value'] := v;
  209. end;
  210. procedure AddBool(const AName: string; B: Boolean);
  211. begin
  212. if B then
  213. AddStr(Aname,'true')
  214. else
  215. AddStr(Aname,'false');
  216. end;
  217. begin
  218. AddStr('ostarget', Options.OSTarget);
  219. AddStr('cputarget', Options.CPUTarget);
  220. AddStr('mo-dir', Options.MoDir);
  221. AddStr('format', Options.Backend);
  222. AddStr('language', Options.Language);
  223. AddStr('package', Options.DefaultPackageName);
  224. AddBool('hide-protected', Options.HideProtected);
  225. AddBool('warn-no-node', Options.WarnNoNode);
  226. AddBool('show-private', Options.ShowPrivate);
  227. AddBool('stop-on-parser-error', Options.StopOnParseError);
  228. AddBool('parse-impl', Options.InterfaceOnly);
  229. AddBool('dont-trim', Options.DontTrim);
  230. end;
  231. Procedure TXMLFPDocOptions.SaveInputFile(Const AInputFile : String; XML : TXMLDocument; AParent: TDOMElement);
  232. Function GetNextWord(Var s : string) : String;
  233. Const
  234. WhiteSpace = [' ',#9,#10,#13];
  235. var
  236. i,j: integer;
  237. begin
  238. I:=1;
  239. While (I<=Length(S)) and (S[i] in WhiteSpace) do
  240. Inc(I);
  241. J:=I;
  242. While (J<=Length(S)) and (not (S[J] in WhiteSpace)) do
  243. Inc(J);
  244. if (I<=Length(S)) then
  245. Result:=Copy(S,I,J-I);
  246. Delete(S,1,J);
  247. end;
  248. Var
  249. S,W,F,O : String;
  250. begin
  251. S:=AInputFile;
  252. O:='';
  253. F:='';
  254. While (S<>'') do
  255. begin
  256. W:=GetNextWord(S);
  257. If (W<>'') then
  258. begin
  259. if W[1]='-' then
  260. begin
  261. if (O<>'') then
  262. O:=O+' ';
  263. o:=O+W;
  264. end
  265. else
  266. F:=W;
  267. end;
  268. end;
  269. AParent['file']:=F;
  270. AParent['options']:=O;
  271. end;
  272. Procedure TXMLFPDocOptions.SaveDescription(Const ADescription : String; XML : TXMLDocument; AParent: TDOMElement);
  273. begin
  274. AParent['file']:=ADescription;
  275. end;
  276. Procedure TXMLFPDocOptions.SavePackage(APackage: TFPDocPackage; XML : TXMLDocument; AParent: TDOMElement);
  277. var
  278. i: integer;
  279. E,PE : TDomElement;
  280. begin
  281. AParent['name']:=APackage.Name;
  282. AParent['output']:=APackage.Output;
  283. AParent['content']:=APackage.ContentFile;
  284. // Units
  285. PE:=XML.CreateElement('units');
  286. AParent.AppendChild(PE);
  287. for i:=0 to APackage.Inputs.Count-1 do
  288. begin
  289. E:=XML.CreateElement('unit');
  290. PE.AppendChild(E);
  291. SaveInputFile(APackage.Inputs[i],XML,E);
  292. end;
  293. // Descriptions
  294. PE:=XML.CreateElement('descriptions');
  295. AParent.AppendChild(PE);
  296. for i:=0 to APackage.Descriptions.Count-1 do
  297. begin
  298. E:=XML.CreateElement('description');
  299. PE.AppendChild(E);
  300. SaveDescription(APackage.Descriptions[i],XML,E);
  301. end;
  302. end;
  303. constructor TXMLFPDocOptions.Create(AOwner: TComponent);
  304. begin
  305. inherited Create(AOwner);
  306. FMacros:=TStringList.Create;
  307. end;
  308. destructor TXMLFPDocOptions.Destroy;
  309. begin
  310. FreeAndNil(FMacros);
  311. inherited Destroy;
  312. end;
  313. procedure TXMLFPDocOptions.DoMacro(Sender: TObject; const TagString: String;
  314. TagParams: TStringList; out ReplaceText: String);
  315. begin
  316. ReplaceText:=FMacros.Values[TagString];
  317. end;
  318. Function TXMLFPDocOptions.ExpandMacrosInFile(AFileName : String) : TStream;
  319. Var
  320. F : TFileStream;
  321. T : TTemplateParser;
  322. begin
  323. F:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
  324. try
  325. Result:=TMemoryStream.Create;
  326. try
  327. T:=TTemplateParser.Create;
  328. try
  329. T.StartDelimiter:='$(';
  330. T.EndDelimiter:=')';
  331. T.AllowTagParams:=true;
  332. T.OnReplaceTag:=@DoMacro;
  333. T.ParseStream(F,Result);
  334. finally
  335. T.Free;
  336. end;
  337. except
  338. FreeAndNil(Result);
  339. Raise;
  340. end;
  341. finally
  342. F.Free;
  343. end;
  344. end;
  345. procedure TXMLFPDocOptions.LoadOptionsFromFile(AProject: TFPDocProject; const AFileName: String);
  346. Var
  347. XML : TXMLDocument;
  348. S : TStream;
  349. begin
  350. If ExpandMacros then
  351. S:=ExpandMacrosInFile(AFileName)
  352. else
  353. S:=TFileStream.Create(AFileName,fmOpenRead or fmShareDenyWrite);
  354. try
  355. ReadXMLFile(XML,S,AFileName);
  356. try
  357. LoadFromXML(AProject,XML);
  358. finally
  359. FreeAndNil(XML);
  360. end;
  361. finally
  362. S.Free;
  363. end;
  364. end;
  365. procedure TXMLFPDocOptions.LoadFromXML(AProject: TFPDocProject;
  366. XML: TXMLDocument);
  367. Var
  368. E : TDOMElement;
  369. N : TDomNode;
  370. begin
  371. E:=XML.DocumentElement;
  372. if (E.NodeName<>'docproject') then
  373. Error(SErrInvalidRootNode,[E.NodeName]);
  374. N:=E.FindNode('packages');
  375. If (N=Nil) or (N.NodeType<>ELEMENT_NODE) then
  376. Error(SErrNoPackagesNode);
  377. LoadPackages(AProject.Packages,N as TDomElement);
  378. N:=E.FindNode('options');
  379. If (N<>Nil) and (N.NodeType=ELEMENT_NODE) then
  380. LoadEngineOptions(AProject.Options,N as TDOMElement);
  381. end;
  382. Procedure TXMLFPDocOptions.SaveOptionsToFile(AProject: TFPDocProject; const AFileName: String);
  383. Var
  384. XML : TXMLDocument;
  385. begin
  386. XML:=TXMLDocument.Create;
  387. try
  388. SaveToXML(AProject,XML);
  389. WriteXMLFile(XML, AFileName);
  390. finally
  391. XML.Free;
  392. end;
  393. end;
  394. end.