fpdocxmlopts.pas 11 KB

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