makeskel.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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 Usage;
  146. begin
  147. Writeln('Usage : ',ExtractFileName(Paramstr(0)),' [options]');
  148. Writeln('Where [options] is one or more of :');
  149. Writeln(' --descr=filename Filename for update.');
  150. Writeln(' --disable-arguments Do not create nodes for function arguments.');
  151. Writeln(' --disable-errors Do not create errors node.');
  152. Writeln(' --disable-function-results');
  153. Writeln(' Do not create nodes for function arguments.');
  154. Writeln(' --disable-private Do not create nodes for class private fields.');
  155. Writeln(' --disable-protected Do not create nodes for class protected fields.');
  156. Writeln(' --disable-seealso Do not create seealso node.');
  157. Writeln(' --emit-class-separator');
  158. Writeln(' Emit descriptive comment between classes.');
  159. Writeln(' --help Emit help.');
  160. Writeln(' --input=cmdline Input file to create skeleton for.');
  161. Writeln(' Use options are as for compiler.');
  162. Writeln(' --lang=language Use selected language.');
  163. Writeln(' --output=filename Send output to file.');
  164. Writeln(' --package=name Specify package name (mandatory).');
  165. Writeln(' --update Update mode. Output only missing nodes.');
  166. end;
  167. procedure ParseOption(const s: String);
  168. procedure AddToFileList(List: TStringList; const FileName: String);
  169. var
  170. f: Text;
  171. s: String;
  172. begin
  173. if Copy(FileName, 1, 1) = '@' then
  174. begin
  175. Assign(f, Copy(FileName, 2, Length(FileName)));
  176. Reset(f);
  177. while not EOF(f) do
  178. begin
  179. ReadLn(f, s);
  180. List.Add(s);
  181. end;
  182. Close(f);
  183. end else
  184. List.Add(FileName);
  185. end;
  186. var
  187. i: Integer;
  188. Cmd, Arg: String;
  189. begin
  190. if (s = '-h') or (s = '--help') then
  191. CmdLineAction := actionHelp
  192. else if s = '--update' then
  193. UpdateMode := True
  194. else if s = '--disable-arguments' then
  195. DisableArguments := True
  196. else if s = '--disable-errors' then
  197. DisableErrors := True
  198. else if s = '--disable-function-results' then
  199. DisableFunctionResults := True
  200. else if s = '--disable-seealso' then
  201. DisableSeealso := True
  202. else if s = '--disable-private' then
  203. DisablePrivate := True
  204. else if s = '--disable-protected' then
  205. begin
  206. DisableProtected := True;
  207. DisablePrivate :=True;
  208. end
  209. else if s = '--emitclassseparator' then
  210. EmitClassSeparator := True
  211. else
  212. begin
  213. i := Pos('=', s);
  214. if i > 0 then
  215. begin
  216. Cmd := Copy(s, 1, i - 1);
  217. Arg := Copy(s, i + 1, Length(s));
  218. end else
  219. begin
  220. Cmd := s;
  221. SetLength(Arg, 0);
  222. end;
  223. if (Cmd = '-i') or (Cmd = '--input') then
  224. AddToFileList(InputFiles, Arg)
  225. else if (Cmd = '-l') or (Cmd = '--lang') then
  226. DocLang := Arg
  227. else if (Cmd = '-o') or (Cmd = '--output') then
  228. OutputName := Arg
  229. else if Cmd = '--package' then
  230. PackageName := Arg
  231. else if Cmd = '--descr' then
  232. begin
  233. if FileExists(Arg) then
  234. DescrFiles.Add(Arg);
  235. end
  236. else
  237. WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
  238. end;
  239. end;
  240. procedure ParseCommandLine;
  241. Const
  242. {$IFDEF Unix}
  243. MoFileTemplate = '/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo';
  244. {$ELSE}
  245. MoFileTemplate ='intl/makeskel.%s.mo';
  246. {$ENDIF}
  247. var
  248. MOFilename: string;
  249. i: Integer;
  250. begin
  251. DocLang:='';
  252. for i := 1 to ParamCount do
  253. ParseOption(ParamStr(i));
  254. If (DocLang<>'') then
  255. begin
  256. MOFilename:=Format(MOFileTemplate,[DocLang]);
  257. if FileExists(MOFilename) then
  258. gettext.TranslateResourceStrings(MoFileName)
  259. else
  260. writeln('NOTE: unable to find tranlation file ',MOFilename);
  261. // Translate internal documentation strings
  262. TranslateDocStrings(DocLang);
  263. end;
  264. end;
  265. var
  266. i,j: Integer;
  267. Module: TPasModule;
  268. begin
  269. InitOptions;
  270. ParseCommandLine;
  271. WriteLn(STitle);
  272. WriteLn(SCopyright);
  273. WriteLn;
  274. if CmdLineAction = actionHelp then
  275. Usage
  276. else
  277. begin
  278. // Action is to create the XML skeleton
  279. if Length(PackageName) = 0 then
  280. begin
  281. WriteLn(SNoPackageNameProvided);
  282. Halt(2);
  283. end;
  284. if DescrFiles.IndexOf(OutputName)<>-1 then
  285. begin
  286. Writeln(SOutputMustNotBeDescr);
  287. Halt(3)
  288. end;
  289. Assign(f, OutputName);
  290. Rewrite(f);
  291. WriteLn(f, '<?xml version="1.0" encoding="ISO8859-1"?>');
  292. WriteLn(f, '<fpdoc-descriptions>');
  293. WriteLn(f, '<package name="', PackageName, '">');
  294. // Process all source files
  295. for i := 0 to InputFiles.Count - 1 do
  296. begin
  297. Engine := TSkelEngine.Create;
  298. try
  299. try
  300. Engine.SetPackageName(PackageName);
  301. if UpdateMode then
  302. For J:=0 to DescrFiles.Count-1 do
  303. Engine.AddDocFile(DescrFiles[J]);
  304. Module := ParseSource(Engine, InputFiles[i], OSTarget, CPUTarget);
  305. WriteLn(f, '</module> <!-- ', Module.Name, ' -->');
  306. except
  307. on e:EFileNotFoundError do
  308. begin
  309. Writeln(StdErr,' file ', e.message, ' not found');
  310. close(f);
  311. Halt(1);
  312. end;
  313. end;
  314. finally
  315. Engine.Free;
  316. end;
  317. end;
  318. WriteLn(f, '</package>');
  319. WriteLn(f, '</fpdoc-descriptions>');
  320. Close(f);
  321. WriteLn(SDone);
  322. end;
  323. FreeOptions;
  324. end.
  325. {
  326. $Log$
  327. Revision 1.14 2004-11-15 18:00:18 michael
  328. + Added help screen
  329. Revision 1.13 2004/09/13 16:04:52 peter
  330. * fix nested for-loop with same index
  331. Revision 1.12 2004/08/29 15:32:41 michael
  332. + More intelligent handling of nodes. Do not write unused nodes.
  333. Revision 1.11 2004/08/28 18:18:59 michael
  334. + Do not write descr nodes for module when updating
  335. Revision 1.10 2004/08/28 18:15:14 michael
  336. + Check whether outputfile not in inputfilenames
  337. Revision 1.9 2004/08/28 18:04:06 michael
  338. + Added update mode
  339. Revision 1.8 2004/08/25 07:16:43 michael
  340. + Improved translation handling
  341. Revision 1.7 2004/08/24 14:48:25 michael
  342. + Translate now called correctly...
  343. Revision 1.6 2004/05/01 20:13:40 marco
  344. * got fed up with exceptions on file not found. Fileresolver now raises a
  345. EFileNotFound error, and makeskel catches and exists gracefully
  346. Revision 1.5 2003/11/28 12:51:37 sg
  347. * Added support for source references
  348. Revision 1.4 2003/09/02 13:26:47 mattias
  349. MG: makeskel now ignores missing translation file
  350. Revision 1.3 2003/05/07 16:31:32 sg
  351. * Fixed a severe memory corruption problem on termination
  352. Revision 1.2 2003/03/28 13:01:36 michael
  353. + Patch from Charlie/iNQ to work with new scanner/parser
  354. Revision 1.1 2003/03/17 23:03:20 michael
  355. + Initial import in CVS
  356. }