makeskel.pp 10 KB

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