makeskel.pp 11 KB

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