makeskel.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. {
  2. $Id$
  3. FPDoc - Free Pascal Documentation Tool
  4. Copyright (C) 2000 - 2003 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. * Skeleton XML description file generator
  7. See the file COPYING, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. }
  13. program MakeSkel;
  14. uses
  15. SysUtils, Classes, Gettext,
  16. dGlobals, PasTree, PParser,PScanner;
  17. resourcestring
  18. STitle = 'MakeSkel - FPDoc skeleton XML description file generator';
  19. SCopyright = '(c) 2000 - 2003 Areca Systems GmbH / Sebastian Guenther, [email protected]';
  20. SCmdLineHelp = 'See documentation for usage.';
  21. SCmdLineInvalidOption = 'Ignoring unknown option "%s"';
  22. SNoPackageNameProvided = 'Please specify a package name with --package=<name>';
  23. SOutputMustNotBeDescr = 'Output file must be different from description filenames.';
  24. SDone = 'Done.';
  25. type
  26. TCmdLineAction = (actionHelp, actionConvert);
  27. TSkelEngine = class(TFPDocEngine)
  28. public
  29. function CreateElement(AClass: TPTreeElement; const AName: String;
  30. AParent: TPasElement; AVisibility :TPasMemberVisibility;
  31. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement; override;
  32. end;
  33. const
  34. CmdLineAction: TCmdLineAction = actionConvert;
  35. OSTarget: String = {$I %FPCTARGETOS%};
  36. CPUTarget: String = {$I %FPCTARGETCPU%};
  37. var
  38. InputFiles, DescrFiles: TStringList;
  39. DocLang: String;
  40. Engine: TSkelEngine;
  41. UpdateMode,
  42. DisableErrors,
  43. DisableSeealso,
  44. DisableArguments,
  45. DisableProtected,
  46. DisablePrivate,
  47. DisableFunctionResults: Boolean;
  48. EmitClassSeparator: Boolean;
  49. PackageName, OutputName: String;
  50. f: Text;
  51. function TSkelEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  52. AParent: TPasElement; AVisibility : TPasMemberVisibility;
  53. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  54. Function WriteThisNode(APasElement : TPasElement) : Boolean;
  55. begin
  56. Result:=Assigned(AParent) and (Length(AName) > 0) and
  57. (not DisableArguments or (APasElement.ClassType <> TPasArgument)) and
  58. (not DisableFunctionResults or (APasElement.ClassType <> TPasResultElement)) and
  59. (not DisablePrivate or (AVisibility<>visPrivate)) and
  60. (not DisableProtected or (AVisibility<>visProtected));
  61. If Result and updateMode then
  62. begin
  63. Result:=FindDocNode(APasElement)=Nil;
  64. If Result then
  65. Writeln(stderr,'Creating documentation for new node ',APasElement.PathName);
  66. end;
  67. end;
  68. Function WriteOnlyShort(APasElement : TPasElement) : Boolean;
  69. begin
  70. Result:=(APasElement.ClassType=TPasArgument) or
  71. (APasElement.ClassType=TPasResultElement) or
  72. (APasElement.ClassType=TPasEnumValue);
  73. end;
  74. Function IsTypeVarConst(APasElement : TPasElement) : Boolean;
  75. begin
  76. With APasElement do
  77. Result:=(InheritsFrom(TPasType) and not InheritsFrom(TPasClassType)) or
  78. (InheritsFrom(TPasResString)) or
  79. (InheritsFrom(TPasVariable));
  80. end;
  81. begin
  82. Result := AClass.Create(AName, AParent);
  83. if AClass.InheritsFrom(TPasModule) then
  84. CurModule := TPasModule(Result);
  85. if Result.ClassType = TPasModule then
  86. begin
  87. WriteLn(f);
  88. WriteLn(f, '<!--');
  89. WriteLn(f, ' ====================================================================');
  90. WriteLn(f, ' ', Result.Name);
  91. WriteLn(f, ' ====================================================================');
  92. WriteLn(f, '-->');
  93. WriteLn(f);
  94. WriteLn(f, '<module name="', Result.Name, '">');
  95. if not UpdateMode then
  96. begin
  97. WriteLn(f, '<short></short>');
  98. WriteLn(f, '<descr>');
  99. WriteLn(f, '</descr>');
  100. end;
  101. end
  102. else if WriteThisNode(Result) then
  103. begin
  104. WriteLn(f);
  105. if EmitClassSeparator and (Result.ClassType = TPasClassType) then
  106. begin
  107. WriteLn(f, '<!--');
  108. WriteLn(f, ' ********************************************************************');
  109. WriteLn(f, ' ', Result.PathName);
  110. WriteLn(f, ' ********************************************************************');
  111. WriteLn(f, '-->');
  112. WriteLn(f);
  113. end;
  114. Writeln(F,'<!-- ', Result.ElementTypeName,' Visibility: ',VisibilityNames[AVisibility], ' -->');
  115. WriteLn(f,'<element name="', Result.FullName, '">');
  116. WriteLn(f, '<short></short>');
  117. if Not WriteOnlyShort(Result) then
  118. begin
  119. WriteLn(f, '<descr>');
  120. WriteLn(f, '</descr>');
  121. if not (DisableErrors or IsTypeVarConst(Result)) then
  122. begin
  123. WriteLn(f, '<errors>');
  124. WriteLn(f, '</errors>');
  125. end;
  126. if not DisableSeealso then
  127. begin
  128. WriteLn(f, '<seealso>');
  129. WriteLn(f, '</seealso>');
  130. end;
  131. end;
  132. WriteLn(f, '</element>');
  133. end;
  134. end;
  135. procedure InitOptions;
  136. begin
  137. InputFiles := TStringList.Create;
  138. DescrFiles := TStringList.Create;
  139. end;
  140. procedure FreeOptions;
  141. begin
  142. DescrFiles.Free;
  143. InputFiles.Free;
  144. end;
  145. procedure ParseOption(const s: String);
  146. procedure AddToFileList(List: TStringList; const FileName: String);
  147. var
  148. f: Text;
  149. s: String;
  150. begin
  151. if Copy(FileName, 1, 1) = '@' then
  152. begin
  153. Assign(f, Copy(FileName, 2, Length(FileName)));
  154. Reset(f);
  155. while not EOF(f) do
  156. begin
  157. ReadLn(f, s);
  158. List.Add(s);
  159. end;
  160. Close(f);
  161. end else
  162. List.Add(FileName);
  163. end;
  164. var
  165. i: Integer;
  166. Cmd, Arg: String;
  167. begin
  168. if (s = '-h') or (s = '--help') then
  169. CmdLineAction := actionHelp
  170. else if s = '--update' then
  171. UpdateMode := True
  172. else if s = '--disable-arguments' then
  173. DisableArguments := True
  174. else if s = '--disable-errors' then
  175. DisableErrors := True
  176. else if s = '--disable-function-results' then
  177. DisableFunctionResults := True
  178. else if s = '--disable-seealso' then
  179. DisableSeealso := True
  180. else if s = '--disable-private' then
  181. DisablePrivate := True
  182. else if s = '--disable-protected' then
  183. begin
  184. DisableProtected := True;
  185. DisablePrivate :=True;
  186. end
  187. else if s = '--emitclassseparator' then
  188. EmitClassSeparator := True
  189. else
  190. begin
  191. i := Pos('=', s);
  192. if i > 0 then
  193. begin
  194. Cmd := Copy(s, 1, i - 1);
  195. Arg := Copy(s, i + 1, Length(s));
  196. end else
  197. begin
  198. Cmd := s;
  199. SetLength(Arg, 0);
  200. end;
  201. if (Cmd = '-i') or (Cmd = '--input') then
  202. AddToFileList(InputFiles, Arg)
  203. else if (Cmd = '-l') or (Cmd = '--lang') then
  204. DocLang := Arg
  205. else if (Cmd = '-o') or (Cmd = '--output') then
  206. OutputName := Arg
  207. else if Cmd = '--package' then
  208. PackageName := Arg
  209. else if Cmd = '--descr' then
  210. begin
  211. if FileExists(Arg) then
  212. DescrFiles.Add(Arg);
  213. end
  214. else
  215. WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
  216. end;
  217. end;
  218. procedure ParseCommandLine;
  219. Const
  220. {$IFDEF Unix}
  221. MoFileTemplate = '/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo';
  222. {$ELSE}
  223. MoFileTemplate ='intl/makeskel.%s.mo';
  224. {$ENDIF}
  225. var
  226. MOFilename: string;
  227. i: Integer;
  228. begin
  229. DocLang:='';
  230. for i := 1 to ParamCount do
  231. ParseOption(ParamStr(i));
  232. If (DocLang<>'') then
  233. begin
  234. MOFilename:=Format(MOFileTemplate,[DocLang]);
  235. if FileExists(MOFilename) then
  236. gettext.TranslateResourceStrings(MoFileName)
  237. else
  238. writeln('NOTE: unable to find tranlation file ',MOFilename);
  239. // Translate internal documentation strings
  240. TranslateDocStrings(DocLang);
  241. end;
  242. end;
  243. var
  244. i: Integer;
  245. Module: TPasModule;
  246. begin
  247. InitOptions;
  248. ParseCommandLine;
  249. WriteLn(STitle);
  250. WriteLn(SCopyright);
  251. WriteLn;
  252. if CmdLineAction = actionHelp then
  253. WriteLn(SCmdLineHelp)
  254. else
  255. begin
  256. // Action is to create the XML skeleton
  257. if Length(PackageName) = 0 then
  258. begin
  259. WriteLn(SNoPackageNameProvided);
  260. Halt(2);
  261. end;
  262. if DescrFiles.IndexOf(OutputName)<>-1 then
  263. begin
  264. Writeln(SOutputMustNotBeDescr);
  265. Halt(3)
  266. end;
  267. Assign(f, OutputName);
  268. Rewrite(f);
  269. WriteLn(f, '<?xml version="1.0" encoding="ISO8859-1"?>');
  270. WriteLn(f, '<fpdoc-descriptions>');
  271. WriteLn(f, '<package name="', PackageName, '">');
  272. // Process all source files
  273. for i := 0 to InputFiles.Count - 1 do
  274. begin
  275. Engine := TSkelEngine.Create;
  276. try
  277. try
  278. Engine.SetPackageName(PackageName);
  279. if UpdateMode then
  280. For I:=0 to DescrFiles.Count-1 do
  281. Engine.AddDocFile(DescrFiles[i]);
  282. Module := ParseSource(Engine, InputFiles[i], OSTarget, CPUTarget);
  283. WriteLn(f, '</module> <!-- ', Module.Name, ' -->');
  284. except
  285. on e:EFileNotFoundError do
  286. begin
  287. Writeln(StdErr,' file ', e.message, ' not found');
  288. close(f);
  289. Halt(1);
  290. end;
  291. end;
  292. finally
  293. Engine.Free;
  294. end;
  295. end;
  296. WriteLn(f, '</package>');
  297. WriteLn(f, '</fpdoc-descriptions>');
  298. Close(f);
  299. end;
  300. FreeOptions;
  301. WriteLn(SDone);
  302. end.
  303. {
  304. $Log$
  305. Revision 1.12 2004-08-29 15:32:41 michael
  306. + More intelligent handling of nodes. Do not write unused nodes.
  307. Revision 1.11 2004/08/28 18:18:59 michael
  308. + Do not write descr nodes for module when updating
  309. Revision 1.10 2004/08/28 18:15:14 michael
  310. + Check whether outputfile not in inputfilenames
  311. Revision 1.9 2004/08/28 18:04:06 michael
  312. + Added update mode
  313. Revision 1.8 2004/08/25 07:16:43 michael
  314. + Improved translation handling
  315. Revision 1.7 2004/08/24 14:48:25 michael
  316. + Translate now called correctly...
  317. Revision 1.6 2004/05/01 20:13:40 marco
  318. * got fed up with exceptions on file not found. Fileresolver now raises a
  319. EFileNotFound error, and makeskel catches and exists gracefully
  320. Revision 1.5 2003/11/28 12:51:37 sg
  321. * Added support for source references
  322. Revision 1.4 2003/09/02 13:26:47 mattias
  323. MG: makeskel now ignores missing translation file
  324. Revision 1.3 2003/05/07 16:31:32 sg
  325. * Fixed a severe memory corruption problem on termination
  326. Revision 1.2 2003/03/28 13:01:36 michael
  327. + Patch from Charlie/iNQ to work with new scanner/parser
  328. Revision 1.1 2003/03/17 23:03:20 michael
  329. + Initial import in CVS
  330. }