fpdocxmlopts.pas 12 KB

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