fpdocxmlopts.pas 12 KB

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