rstconv.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Sebastian Guenther
  5. Added .rc and OS/2 MSG support in 2002 by Yuri Prokushev
  6. .rst resource string table file converter.
  7. See the file COPYING.FPC, 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. {$MODE objfpc}
  14. {$H+}
  15. program rstconv;
  16. uses sysutils, classes;
  17. resourcestring
  18. help =
  19. 'rstconv [-h|--help] Displays this help'+LineEnding+
  20. 'rstconv options Convert rst file'+LineEnding+LineEnding+
  21. 'Options are:'+LineEnding+
  22. ' -i file Use specified file instead of stdin as input .rst (OPTIONAL)'+LineEnding+
  23. ' -o file Write output to specified file (REQUIRED)'+LineEnding+
  24. ' -f format Specifies the output format:'+LineEnding+
  25. ' po GNU gettext .po (portable) format (DEFAULT)'+LineEnding+
  26. ' msg IBM OS/2 MSG file format'+LineEnding+
  27. ' rc Resource compiler .rc format'+LineEnding+LineEnding+
  28. 'OS/2 MSG file only options are:'+LineEnding+
  29. ' -c identifier Specifies the component identifier (REQUIRED).'+LineEnding+
  30. ' Identifier is any three chars in upper case.'+LineEnding+
  31. ' -n number Specifies the first message number [1-9999] (OPTIONAL).'+LineEnding+LineEnding+
  32. 'Resource compiler script only options are:'+LineEnding+
  33. ' -s Use STRINGTABLE instead of MESSAGETABLE'+LineEnding+
  34. ' -c identifier Use identifier as ID base (ID+n) (OPTIONAL)'+LineEnding+
  35. ' -n number Specifies the first ID number (OPTIONAL)'+LineEnding;
  36. InvalidOption = 'Invalid option - ';
  37. RequiredOption = 'Required option is absent - ';
  38. OptionAlreadySpecified = 'Option has already been specified - ';
  39. NoOutFilename = 'No output filename specified';
  40. InvalidOutputFormat = 'Invalid output format -';
  41. MessageNumberTooBig = 'Message number too big';
  42. InvalidRange = 'Invalid range of the first message number';
  43. type
  44. TConstItem = class(TCollectionItem)
  45. public
  46. ModuleName, ConstName, Value: String;
  47. end;
  48. var
  49. InFilename, OutFilename: String;
  50. ConstItems: TCollection;
  51. Identifier: String;
  52. FirstMessage: Word;
  53. MessageTable: Boolean;
  54. procedure ReadRSTFile;
  55. var
  56. f: Text;
  57. s: String;
  58. item: TConstItem;
  59. DotPos, EqPos, i, j: Integer;
  60. begin
  61. Assign(f, InFilename);
  62. Reset(f);
  63. while not eof(f) do begin
  64. ReadLn(f, s);
  65. If (Length(S)=0) or (S[1]='#') then
  66. continue;
  67. item := TConstItem(ConstItems.Add);
  68. DotPos := Pos('.', s);
  69. EqPos := Pos('=', s);
  70. if DotPos > EqPos then // paranoia checking.
  71. DotPos := 0;
  72. item.ModuleName := Copy(s, 1, DotPos - 1);
  73. item.ConstName := Copy(s, DotPos + 1, EqPos - DotPos - 1);
  74. item.Value := '';
  75. i := EqPos + 1;
  76. while i <= Length(s) do begin
  77. if s[i] = '''' then begin
  78. Inc(i);
  79. j := i;
  80. while (i <= Length(s)) and (s[i] <> '''') do
  81. Inc(i);
  82. item.Value := item.Value + Copy(s, j, i - j);
  83. Inc(i);
  84. end else if s[i] = '#' then begin
  85. Inc(i);
  86. j := i;
  87. while (i <= Length(s)) and (s[i] in ['0'..'9']) do
  88. Inc(i);
  89. item.Value := item.Value + Chr(StrToInt(Copy(s, j, i - j)));
  90. end else if s[i] = '+' then begin
  91. ReadLn(f, s);
  92. i := 1;
  93. end else
  94. Inc(i);
  95. end;
  96. end;
  97. Close(f);
  98. end;
  99. procedure ConvertToGettextPO;
  100. var
  101. i, j: Integer;
  102. f: Text;
  103. item: TConstItem;
  104. s: String;
  105. c: Char;
  106. begin
  107. Assign(f, OutFilename);
  108. Rewrite(f);
  109. for i := 0 to ConstItems.Count - 1 do begin
  110. item := TConstItem(ConstItems.items[i]);
  111. // Convert string to C-style syntax
  112. s := '';
  113. for j := 1 to Length(item.Value) do begin
  114. c := item.Value[j];
  115. case c of
  116. #9: s := s + '\t';
  117. #10: s := s + '\n';
  118. {$IFNDEF UNIX}
  119. #13: ;
  120. #1..#8, #11..#12, #14..#31, #128..#255:
  121. {$ELSE}
  122. #1..#8, #11..#31, #128..#255:
  123. {$ENDIF}
  124. s := s + '\' +
  125. Chr(Ord(c) shr 6 + 48) +
  126. Chr((Ord(c) shr 3) and 7 + 48) +
  127. Chr(Ord(c) and 7 + 48);
  128. '\': s := s + '\\';
  129. '"': s := s + '\"';
  130. else s := s + c;
  131. end;
  132. end;
  133. // Write msg entry
  134. WriteLn(f, '#: ', item.ModuleName, ':', item.ConstName);
  135. WriteLn(f, 'msgid "', s, '"');
  136. WriteLn(f, 'msgstr ""');
  137. WriteLn(f);
  138. end;
  139. Close(f);
  140. end;
  141. // This routine stores rst file in rc format. Can be written as MESSAGETABLE
  142. // as STRINGTABLE. Beware! OS/2 RC doesn't support lines longer whan 255 chars.
  143. procedure ConvertToRC;
  144. var
  145. i, j: Integer;
  146. f: Text;
  147. item: TConstItem;
  148. s: String;
  149. c: Char;
  150. begin
  151. Assign(f, OutFilename);
  152. Rewrite(f);
  153. If MessageTable then
  154. WriteLn(F, 'MESSAGETABLE')
  155. else
  156. WriteLn(F, 'STRINGTABLE');
  157. WriteLn(F, 'BEGIN');
  158. If Identifier<>'' then WriteLn(F, '#define ', Identifier);
  159. for i := 0 to ConstItems.Count - 1 do begin
  160. item := TConstItem(ConstItems.items[i]);
  161. // Convert string to C-style syntax
  162. s := '';
  163. for j := 1 to Length(item.Value) do begin
  164. c := item.Value[j];
  165. case c of
  166. #9: s := s + '\t';
  167. #10: s := s + '\n"'#13#10'"';
  168. {$IFNDEF UNIX}
  169. #13: ;
  170. #1..#8, #11..#12, #14..#31, #128..#255:
  171. {$ELSE}
  172. #1..#8, #11..#31, #128..#255:
  173. {$ENDIF}
  174. s := s + '\' +
  175. Chr(Ord(c) shr 6 + 48) +
  176. Chr((Ord(c) shr 3) and 7 + 48) +
  177. Chr(Ord(c) and 7 + 48);
  178. '\': s := s + '\\';
  179. '"': s := s + '\"';
  180. else s := s + c;
  181. end;
  182. end;
  183. // Write msg entry
  184. WriteLn(f, '/* ', item.ModuleName, ':', item.ConstName, '*/');
  185. WriteLn(f, '/* ', s, ' */');
  186. If Identifier<>'' then Write(F, Identifier, '+');
  187. WriteLn(f, I+FirstMessage,' "', s, '"');
  188. WriteLn(f);
  189. end;
  190. WriteLn(F, 'END');
  191. Close(f);
  192. end;
  193. // This routine stores rst file in OS/2 msg format. This format is preffered
  194. // for help screens, messages, etc.
  195. procedure ConvertToOS2MSG;
  196. var
  197. i, j: Integer;
  198. f: Text;
  199. item: TConstItem;
  200. s: String;
  201. begin
  202. If (ConstItems.Count+FirstMessage-1)>9999 then
  203. begin
  204. WriteLn(MessageNumberTooBig);
  205. Halt(1);
  206. end;
  207. Identifier:=Copy(UpperCase(Identifier), 1, 3);
  208. Assign(f, OutFilename);
  209. Rewrite(f);
  210. WriteLn(f, Identifier);
  211. // Fake entry, because MKMSGF limitation
  212. WriteLn(f, Format('%s%.4d?: ',[Identifier, FirstMessage-1]));
  213. for i := 0 to ConstItems.Count - 1 do begin
  214. item := TConstItem(ConstItems.items[i]);
  215. // Prepare comment string
  216. // Convert string to C-style syntax
  217. s := '';
  218. j:=1;
  219. while j<=Length(item.Value) do
  220. begin
  221. if copy(item.Value, j, 2)=#13#10 then
  222. begin
  223. s:=s+#13#10';';
  224. Inc(j, 2);
  225. end else begin
  226. s := s + item.Value[j];
  227. Inc(j);
  228. end;
  229. end;
  230. // Write msg entry
  231. WriteLn(f, ';', item.ModuleName, '.', item.ConstName);
  232. WriteLn(f, Format(';%s%.4dP: %s %%0',[Identifier, i+FirstMessage, s]));
  233. WriteLn(f, Format('%s%.4dP: %s %%0',[Identifier, i+FirstMessage, Item.Value]));
  234. end;
  235. Close(f);
  236. end;
  237. type
  238. TConversionProc = procedure;
  239. var
  240. i: Integer;
  241. ConversionProc: TConversionProc;
  242. OutputFormat: String;
  243. begin
  244. if (ParamStr(1) = '-h') or (ParamStr(1) = '--help') then begin
  245. WriteLn(help);
  246. exit;
  247. end;
  248. ConversionProc := @ConvertToGettextPO;
  249. OutputFormat:='';
  250. Identifier:='';
  251. FirstMessage:=0;
  252. MessageTable:=True;
  253. i := 1;
  254. while i <= ParamCount do begin
  255. if ParamStr(i) = '-i' then begin
  256. if InFilename <> '' then begin
  257. WriteLn(StdErr, OptionAlreadySpecified, '-i');
  258. Halt(1);
  259. end;
  260. InFilename := ParamStr(i + 1);
  261. Inc(i, 2);
  262. end else if ParamStr(i) = '-o' then begin
  263. if OutFilename <> '' then begin
  264. WriteLn(StdErr, OptionAlreadySpecified, '-o');
  265. Halt(1);
  266. end;
  267. OutFilename := ParamStr(i + 1);
  268. Inc(i, 2);
  269. end else if ParamStr(i) = '-f' then begin
  270. if OutputFormat <> '' then begin
  271. WriteLn(StdErr, OptionAlreadySpecified, '-f');
  272. Halt(1);
  273. end;
  274. if ParamStr(i + 1) = 'po' then
  275. OutputFormat:='po'
  276. else if ParamStr(i + 1) = 'msg' then begin
  277. OutputFormat:='msg';
  278. ConversionProc := @ConvertToOS2MSG;
  279. end else if ParamStr(i + 1) = 'rc' then begin
  280. OutputFormat:='rc';
  281. ConversionProc := @ConvertToRC;
  282. end else begin
  283. WriteLn(StdErr, InvalidOutputFormat, ParamStr(i + 1));
  284. Halt(1);
  285. end;
  286. Inc(i, 2);
  287. end else if ParamStr(i) = '-c' then begin
  288. if Identifier <> '' then begin
  289. WriteLn(StdErr, OptionAlreadySpecified, '-c');
  290. Halt(1);
  291. end;
  292. Identifier:=ParamStr(i+1);
  293. Inc(i, 2);
  294. end else if ParamStr(i) = '-s' then begin
  295. if not MessageTable then begin
  296. WriteLn(StdErr, OptionAlreadySpecified, '-s');
  297. Halt(1);
  298. end;
  299. MessageTable:=False;
  300. Inc(i);
  301. end else if ParamStr(i) = '-n' then begin
  302. if FirstMessage <> 0 then begin
  303. WriteLn(StdErr, OptionAlreadySpecified, '-n');
  304. Halt(1);
  305. end;
  306. try
  307. FirstMessage := StrToInt(ParamStr(i + 1));
  308. If (FirstMessage<1) then raise EConvertError.Create(InvalidRange+' '+ParamStr(i+1));
  309. except
  310. on EConvertError do
  311. begin
  312. WriteLn(StdErr, InvalidOption, ParamStr(i));
  313. Halt(1);
  314. end;
  315. end;
  316. Inc(i, 2);
  317. end else begin
  318. WriteLn(StdErr, InvalidOption, ParamStr(i));
  319. Halt(1);
  320. end;
  321. end;
  322. If ((OutputFormat<>'msg') and (OutputFormat<>'rc')) and ((Identifier<>'') or (FirstMessage<>0)) then begin
  323. WriteLn(StdErr, InvalidOption, '');
  324. Halt(1);
  325. end;
  326. If (OutputFormat='msg') and (Identifier='') then begin
  327. WriteLn(StdErr, RequiredOption, '-c');
  328. Halt(1);
  329. end;
  330. if OutFilename = '' then begin
  331. WriteLn(StdErr, NoOutFilename);
  332. Halt(1);
  333. end;
  334. ConstItems := TCollection.Create(TConstItem);
  335. ReadRSTFile;
  336. ConversionProc;
  337. end.
  338. {
  339. $Log$
  340. Revision 1.5 2002-09-30 21:01:37 hajny
  341. + .rc support added by Yuri Prokushev
  342. Revision 1.4 2002/09/22 10:58:25 hajny
  343. + support of IBM MSG files added by Yuri Prokushev
  344. Revision 1.3 2002/09/07 15:40:31 peter
  345. * old logs removed and tabs fixed
  346. }