makeskel.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. 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. begin
  55. Result:=Assigned(AParent) and (Length(AName) > 0) and
  56. (not DisableArguments or (APasElement.ClassType <> TPasArgument)) and
  57. (not DisableFunctionResults or (APasElement.ClassType <> TPasResultElement)) and
  58. (not DisablePrivate or (AVisibility<>visPrivate)) and
  59. (not DisableProtected or (AVisibility<>visProtected));
  60. If Result and updateMode then
  61. begin
  62. Result:=FindDocNode(APasElement)=Nil;
  63. If Result then
  64. Writeln(stderr,'Creating documentation for new node ',APasElement.PathName);
  65. end;
  66. end;
  67. Function WriteOnlyShort(APasElement : TPasElement) : Boolean;
  68. begin
  69. Result:=(APasElement.ClassType=TPasArgument) or
  70. (APasElement.ClassType=TPasResultElement) or
  71. (APasElement.ClassType=TPasEnumValue);
  72. end;
  73. Function IsTypeVarConst(APasElement : TPasElement) : Boolean;
  74. begin
  75. With APasElement do
  76. Result:=(InheritsFrom(TPasType) and not InheritsFrom(TPasClassType)) or
  77. (InheritsFrom(TPasResString)) or
  78. (InheritsFrom(TPasVariable));
  79. end;
  80. begin
  81. Result := AClass.Create(AName, AParent);
  82. if AClass.InheritsFrom(TPasModule) then
  83. CurModule := TPasModule(Result);
  84. if Result.ClassType = TPasModule then
  85. begin
  86. WriteLn(f);
  87. WriteLn(f, '<!--');
  88. WriteLn(f, ' ====================================================================');
  89. WriteLn(f, ' ', Result.Name);
  90. WriteLn(f, ' ====================================================================');
  91. WriteLn(f, '-->');
  92. WriteLn(f);
  93. WriteLn(f, '<module name="', Result.Name, '">');
  94. if not UpdateMode then
  95. begin
  96. WriteLn(f, '<short></short>');
  97. WriteLn(f, '<descr>');
  98. WriteLn(f, '</descr>');
  99. end;
  100. end
  101. else if WriteThisNode(Result) then
  102. begin
  103. WriteLn(f);
  104. if EmitClassSeparator and (Result.ClassType = TPasClassType) then
  105. begin
  106. WriteLn(f, '<!--');
  107. WriteLn(f, ' ********************************************************************');
  108. WriteLn(f, ' ', Result.PathName);
  109. WriteLn(f, ' ********************************************************************');
  110. WriteLn(f, '-->');
  111. WriteLn(f);
  112. end;
  113. Writeln(F,'<!-- ', Result.ElementTypeName,' Visibility: ',VisibilityNames[AVisibility], ' -->');
  114. WriteLn(f,'<element name="', Result.FullName, '">');
  115. WriteLn(f, '<short></short>');
  116. if Not WriteOnlyShort(Result) then
  117. begin
  118. WriteLn(f, '<descr>');
  119. WriteLn(f, '</descr>');
  120. if not (DisableErrors or IsTypeVarConst(Result)) then
  121. begin
  122. WriteLn(f, '<errors>');
  123. WriteLn(f, '</errors>');
  124. end;
  125. if not DisableSeealso then
  126. begin
  127. WriteLn(f, '<seealso>');
  128. WriteLn(f, '</seealso>');
  129. end;
  130. end;
  131. WriteLn(f, '</element>');
  132. end;
  133. end;
  134. procedure InitOptions;
  135. begin
  136. InputFiles := TStringList.Create;
  137. DescrFiles := TStringList.Create;
  138. end;
  139. procedure FreeOptions;
  140. begin
  141. DescrFiles.Free;
  142. InputFiles.Free;
  143. end;
  144. Procedure Usage;
  145. begin
  146. Writeln('Usage : ',ExtractFileName(Paramstr(0)),' [options]');
  147. Writeln('Where [options] is one or more of :');
  148. Writeln(' --descr=filename Filename for update.');
  149. Writeln(' --disable-arguments Do not create nodes for function arguments.');
  150. Writeln(' --disable-errors Do not create errors node.');
  151. Writeln(' --disable-function-results');
  152. Writeln(' Do not create nodes for function arguments.');
  153. Writeln(' --disable-private Do not create nodes for class private fields.');
  154. Writeln(' --disable-protected Do not create nodes for class protected fields.');
  155. Writeln(' --disable-seealso Do not create seealso node.');
  156. Writeln(' --emit-class-separator');
  157. Writeln(' Emit descriptive comment between classes.');
  158. Writeln(' --help Emit help.');
  159. Writeln(' --input=cmdline Input file to create skeleton for.');
  160. Writeln(' Use options are as for compiler.');
  161. Writeln(' --lang=language Use selected language.');
  162. Writeln(' --output=filename Send output to file.');
  163. Writeln(' --package=name Specify package name (mandatory).');
  164. Writeln(' --update Update mode. Output only missing nodes.');
  165. end;
  166. procedure ParseOption(const s: String);
  167. procedure AddToFileList(List: TStringList; const FileName: String);
  168. var
  169. f: Text;
  170. s: String;
  171. begin
  172. if Copy(FileName, 1, 1) = '@' then
  173. begin
  174. Assign(f, Copy(FileName, 2, Length(FileName)));
  175. Reset(f);
  176. while not EOF(f) do
  177. begin
  178. ReadLn(f, s);
  179. List.Add(s);
  180. end;
  181. Close(f);
  182. end else
  183. List.Add(FileName);
  184. end;
  185. var
  186. i: Integer;
  187. Cmd, Arg: String;
  188. begin
  189. if (s = '-h') or (s = '--help') then
  190. CmdLineAction := actionHelp
  191. else if s = '--update' then
  192. UpdateMode := True
  193. else if s = '--disable-arguments' then
  194. DisableArguments := True
  195. else if s = '--disable-errors' then
  196. DisableErrors := True
  197. else if s = '--disable-function-results' then
  198. DisableFunctionResults := True
  199. else if s = '--disable-seealso' then
  200. DisableSeealso := True
  201. else if s = '--disable-private' then
  202. DisablePrivate := True
  203. else if s = '--disable-protected' then
  204. begin
  205. DisableProtected := True;
  206. DisablePrivate :=True;
  207. end
  208. else if s = '--emitclassseparator' then
  209. EmitClassSeparator := True
  210. else
  211. begin
  212. i := Pos('=', s);
  213. if i > 0 then
  214. begin
  215. Cmd := Copy(s, 1, i - 1);
  216. Arg := Copy(s, i + 1, Length(s));
  217. end else
  218. begin
  219. Cmd := s;
  220. SetLength(Arg, 0);
  221. end;
  222. if (Cmd = '-i') or (Cmd = '--input') then
  223. AddToFileList(InputFiles, Arg)
  224. else if (Cmd = '-l') or (Cmd = '--lang') then
  225. DocLang := Arg
  226. else if (Cmd = '-o') or (Cmd = '--output') then
  227. OutputName := Arg
  228. else if Cmd = '--package' then
  229. PackageName := Arg
  230. else if Cmd = '--descr' then
  231. begin
  232. if FileExists(Arg) then
  233. DescrFiles.Add(Arg);
  234. end
  235. else
  236. WriteLn(StdErr, Format(SCmdLineInvalidOption, [s]));
  237. end;
  238. end;
  239. procedure ParseCommandLine;
  240. Const
  241. {$IFDEF Unix}
  242. MoFileTemplate = '/usr/local/share/locale/%s/LC_MESSAGES/makeskel.mo';
  243. {$ELSE}
  244. MoFileTemplate ='intl/makeskel.%s.mo';
  245. {$ENDIF}
  246. var
  247. MOFilename: string;
  248. i: Integer;
  249. begin
  250. DocLang:='';
  251. for i := 1 to ParamCount do
  252. ParseOption(ParamStr(i));
  253. If (DocLang<>'') then
  254. begin
  255. MOFilename:=Format(MOFileTemplate,[DocLang]);
  256. if FileExists(MOFilename) then
  257. gettext.TranslateResourceStrings(MoFileName)
  258. else
  259. writeln('NOTE: unable to find tranlation file ',MOFilename);
  260. // Translate internal documentation strings
  261. TranslateDocStrings(DocLang);
  262. end;
  263. end;
  264. var
  265. i,j: Integer;
  266. Module: TPasModule;
  267. begin
  268. InitOptions;
  269. ParseCommandLine;
  270. WriteLn(STitle);
  271. WriteLn(SCopyright);
  272. WriteLn;
  273. if CmdLineAction = actionHelp then
  274. Usage
  275. else
  276. begin
  277. // Action is to create the XML skeleton
  278. if Length(PackageName) = 0 then
  279. begin
  280. WriteLn(SNoPackageNameProvided);
  281. Halt(2);
  282. end;
  283. if DescrFiles.IndexOf(OutputName)<>-1 then
  284. begin
  285. Writeln(SOutputMustNotBeDescr);
  286. Halt(3)
  287. end;
  288. Assign(f, OutputName);
  289. Rewrite(f);
  290. WriteLn(f, '<?xml version="1.0" encoding="ISO-8859-1"?>');
  291. WriteLn(f, '<fpdoc-descriptions>');
  292. WriteLn(f, '<package name="', PackageName, '">');
  293. // Process all source files
  294. for i := 0 to InputFiles.Count - 1 do
  295. begin
  296. Engine := TSkelEngine.Create;
  297. try
  298. try
  299. Engine.SetPackageName(PackageName);
  300. if UpdateMode then
  301. For J:=0 to DescrFiles.Count-1 do
  302. Engine.AddDocFile(DescrFiles[J]);
  303. Module := ParseSource(Engine, InputFiles[i], OSTarget, CPUTarget);
  304. WriteLn(f, '</module> <!-- ', Module.Name, ' -->');
  305. except
  306. on e:EFileNotFoundError do
  307. begin
  308. Writeln(StdErr,' file ', e.message, ' not found');
  309. close(f);
  310. Halt(1);
  311. end;
  312. end;
  313. finally
  314. Engine.Free;
  315. end;
  316. end;
  317. WriteLn(f, '</package>');
  318. WriteLn(f, '</fpdoc-descriptions>');
  319. Close(f);
  320. WriteLn(SDone);
  321. end;
  322. FreeOptions;
  323. end.