msgdif.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. {
  2. $Id$
  3. This program is part of the Free Pascal run time library.
  4. Copyright (c) 1998-2000 by Peter Vreman
  5. Show the differences between two .msg files
  6. See the file COPYING.FPC, 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. (* May be we need to compare a prefixes of option_help_pages too? *)
  13. (* Currently this is not performed *)
  14. Program messagedif;
  15. {$h+} {Huge strings}
  16. Uses
  17. Strings;
  18. Type
  19. TEnum = String;
  20. TText = String;
  21. PMsg = ^TMsg;
  22. TMsg = Record
  23. Line, ctxt, cnb : Longint;
  24. enum : TEnum;
  25. text : TText;
  26. comment : pchar;
  27. Next,Prev : PMsg;
  28. FileNext,
  29. Equivalent : PMsg;
  30. end;
  31. Var
  32. OrgFileName,DiffFileName : String;
  33. OrgRoot,DiffRoot : PMsg;
  34. OrgFirst,DiffFirst : PMsg;
  35. Last : PMsg;
  36. const
  37. NewFileName = 'new.msg';
  38. Is_interactive : boolean = false;
  39. Procedure GetTranslation( p : PMsg);
  40. var
  41. s : string;
  42. i,j : longint;
  43. begin
  44. i:=pos('_',p^.text);
  45. if (i>0) and (i<=5) then
  46. Writeln(P^.Enum,' type "',copy(p^.text,1,i-1),'" "',copy(p^.text,i+1,255),'"')
  47. else
  48. Writeln(P^.enum,' "',p^.text,'"');
  49. Readln(s);
  50. if s='' then
  51. begin
  52. Is_interactive:=false;
  53. exit;
  54. end;
  55. j:=pos('_',s);
  56. if (j>0) and (j<=5) then
  57. begin
  58. if copy(p^.text,1,i)<>copy(s,1,j) then
  59. Writeln('Different verbosity !!');
  60. p^.text:=s;
  61. end
  62. else
  63. p^.text:=copy(p^.text,1,i)+s;
  64. end;
  65. Function NewMsg (Var RM : PMsg; L : Longint; Const E : TEnum;Const T : TText;C : pchar;NbLn,TxtLn : longint) : PMsg;
  66. Var
  67. P,R : PMsg;
  68. begin
  69. New(P);
  70. with P^ do
  71. begin
  72. Line:=L;
  73. Text:=T;
  74. enum:=E;
  75. comment:=c;
  76. cnb:=NbLn;
  77. ctxt:=TxtLn;
  78. next:=Nil;
  79. prev:=Nil;
  80. filenext:=nil;
  81. equivalent:=nil;
  82. if assigned(last) then
  83. last^.FileNext:=P;
  84. last:=P;
  85. end;
  86. R:=RM;
  87. While (R<>Nil) and (UpCase(R^.enum)>UpCase(P^.Enum)) do
  88. begin
  89. P^.Prev:=R;
  90. R:=R^.next;
  91. end;
  92. if assigned(R) and (UpCase(R^.Enum)=UpCase(P^.Enum)) then
  93. Writeln('Error ',R^.Enum,' duplicate');
  94. P^.Next:=R;
  95. If R<>Nil then
  96. R^.Prev:=P;
  97. If P^.Prev<>Nil then
  98. P^.Prev^.Next:=P
  99. else
  100. RM:=P;
  101. NewMsg:=P;
  102. end;
  103. Procedure PrintList(const name : string;R : PMsg);
  104. var
  105. P : PMsg;
  106. f : text;
  107. begin
  108. P:=R;
  109. Assign(f,name);
  110. Rewrite(f);
  111. while assigned(P) do
  112. begin
  113. Writeln(f,UpCase(P^.Enum));
  114. P:=P^.Next;
  115. end;
  116. Close(f);
  117. end;
  118. Procedure Usage;
  119. begin
  120. Writeln ('Usage : msgdif [-i] orgfile diffile');
  121. Writeln(' optional -i option allows to enter translated messages interactivly');
  122. Writeln('Generates ',NewFileName,' with updated messages');
  123. halt(1)
  124. end;
  125. Procedure ProcessOptions;
  126. var
  127. i,count : longint;
  128. begin
  129. count:=paramcount;
  130. if (count>0) and (UpCase(Paramstr(1))='-I') then
  131. begin
  132. dec(count);
  133. i:=1;
  134. Is_interactive:=true;
  135. end
  136. else
  137. begin
  138. i:=0;
  139. Is_interactive:=false;
  140. end;
  141. If Count<>2 then
  142. Usage;
  143. OrgfileName:=Paramstr(i+1);
  144. DiffFileName:=Paramstr(i+2);
  145. if (OrgFileName=NewFileName) or (DiffFileName=NewFileName) then
  146. begin
  147. Writeln('The file names must be different from ',NewFileName);
  148. Halt(1);
  149. end;
  150. end;
  151. Procedure ProcessFile (FileName : String; Var Root,First : PMsg);
  152. Const
  153. ArrayLength = 65500;
  154. Var F : Text;
  155. S,prevS : String;
  156. J,LineNo,Count,NbLn,TxtLn : Longint;
  157. chararray : array[0..ArrayLength] of char;
  158. currentindex : longint;
  159. c : pchar;
  160. multiline : boolean;
  161. begin
  162. Assign(F,FileName);
  163. Reset(F);
  164. Write ('Processing: ',Filename,'...');
  165. LineNo:=0;
  166. NbLn:=0;
  167. TxtLn:=0;
  168. Count:=0;
  169. currentindex:=0;
  170. Root:=Nil;
  171. First:=nil;
  172. Last:=nil;
  173. PrevS:='';
  174. multiline:=false;
  175. While not eof(f) do
  176. begin
  177. Readln(F,S);
  178. Inc(LineNo);
  179. If multiline then
  180. begin
  181. PrevS:=PrevS+#10+S; Inc(TxtLn);
  182. if (Length(S)<>0) and (S[1]=']') then
  183. multiline:=false;
  184. end
  185. else
  186. if (length(S)>0) and Not (S[1] in ['%','#']) Then
  187. begin
  188. J:=Pos('=',S);
  189. If j<1 then
  190. writeln (Filename,'(',LineNo,') : Invalid entry')
  191. else
  192. begin
  193. chararray[currentindex]:=#0;
  194. c:=strnew(@chararray);
  195. if PrevS<>'' then
  196. NewMsg(Root,LineNo,Copy(PrevS,1,Pos('=',PrevS)-1),
  197. Copy(PrevS,Pos('=',PrevS)+1,Length(PrevS)),c,NbLn,TxtLn)
  198. else
  199. StrDispose(c);
  200. currentindex:=0;
  201. NbLn:=0; TxtLn:=0;
  202. PrevS:=S; Inc(TxtLn);
  203. if S[j+7]='[' then multiline:=true;
  204. if First=nil then
  205. First:=Root;
  206. Inc(Count);
  207. end;
  208. end
  209. else
  210. begin
  211. if currentindex+length(s)+1>ArrayLength then
  212. Writeln('Comment too long : over ',ArrayLength,' chars')
  213. else
  214. begin
  215. strpcopy(@chararray[currentindex],s+#10);
  216. inc(currentindex,length(s)+1);
  217. inc(NbLn);
  218. end;
  219. end;
  220. end;
  221. chararray[currentindex]:=#0;
  222. c:=strnew(@chararray);
  223. if PrevS<>'' then
  224. NewMsg(Root,LineNo,Copy(PrevS,1,Pos('=',PrevS)-1),
  225. Copy(PrevS,Pos('=',PrevS)+1,Length(PrevS)),c,NbLn,TxtLn);
  226. Writeln (' Done. Read ',LineNo,' lines, got ',Count,' constants.');
  227. Close(f);
  228. end;
  229. Procedure ShowDiff (POrg,PDiff : PMsg);
  230. Var
  231. count,orgcount,diffcount : longint;
  232. Procedure NotFound (Org : Boolean; P : PMsg);
  233. begin
  234. With P^ do
  235. If Org Then
  236. Writeln ('Not found in ',DiffFileName,' : ',Enum,' ',OrgFileName,'(',Line,')')
  237. else
  238. Writeln ('Extra in ',DiffFileName,'(',line,') : ',enum);
  239. if org then
  240. inc(orgcount)
  241. else
  242. inc(diffcount);
  243. end;
  244. begin
  245. orgcount:=0;
  246. diffcount:=0;
  247. count:=0;
  248. While (Porg<>Nil) and (PDiff<>Nil) do
  249. begin
  250. // Writeln (POrg^.enum,'<=>',PDiff^.Enum);
  251. If UpCase(Porg^.Enum)>UpCase(PDiff^.Enum) then
  252. begin
  253. NotFound (True,Porg);
  254. POrg:=POrg^.Next
  255. end
  256. else If UpCase(POrg^.enum)=UpCase(PDiff^.Enum) then
  257. begin
  258. inc(count);
  259. POrg^.Equivalent:=PDiff;
  260. PDiff^.Equivalent:=POrg;
  261. POrg:=POrg^.Next;
  262. PDiff:=PDiff^.Next;
  263. end
  264. else
  265. begin
  266. NotFound (False,PDiff);
  267. PDiff:=PDiff^.Next
  268. end;
  269. end;
  270. While POrg<>Nil do
  271. begin
  272. NotFound(True,Porg);
  273. POrg:=pOrg^.Next;
  274. end;
  275. While PDiff<>Nil do
  276. begin
  277. NotFound(False,PDiff);
  278. PDiff:=PDiff^.Next;
  279. end;
  280. Writeln(count,' messages found in common to both files');
  281. Writeln(orgcount,' messages only in ',OrgFileName);
  282. Writeln(diffcount,' messages only in ',DiffFileName);
  283. end;
  284. procedure WriteReorderedFile(FileName : string;orgnext,diffnext : PMsg);
  285. var t,t2,t3 : text;
  286. i,ntcount : longint;
  287. j : integer;
  288. s,s2,s3 : string;
  289. is_msg : boolean;
  290. nextdiffkept : pmsg;
  291. begin
  292. ntcount:=0;
  293. Assign(t,FileName);
  294. Rewrite(t);
  295. Writeln(t,'%%% Reordering of ',DiffFileName,' respective to ',OrgFileName);
  296. Writeln(t,'%%% Contains all comments from ',DiffFileName);
  297. Assign(t2,DiffFileName);
  298. Reset(t2);
  299. Assign(t3,OrgFileName);
  300. Reset(t3);
  301. i:=2;
  302. s:='';s3:='';
  303. nextdiffkept:=diffnext;
  304. while assigned(nextdiffkept) and (nextdiffkept^.equivalent=nil) do
  305. nextdiffkept:=nextdiffkept^.filenext;
  306. { First write the header of diff }
  307. repeat
  308. Readln(t2,s);
  309. is_msg:=(pos('=',s)>1) and (s[1]<>'%') and (s[1]<>'#');
  310. if not is_msg then
  311. begin
  312. Writeln(t,s);
  313. inc(i);
  314. end;
  315. until is_msg;
  316. { Write all messages in Org order }
  317. while assigned(orgnext) do
  318. begin
  319. if not assigned(orgnext^.equivalent) then
  320. begin
  321. { Insert a new error msg with the english comments }
  322. Writeln('New error ',orgnext^.enum,' added');
  323. If Is_interactive then
  324. GetTranslation(orgnext);
  325. Writeln(t,orgnext^.enum,'=',orgnext^.text);
  326. inc(i,orgnext^.ctxt);
  327. Write(t,orgnext^.comment);
  328. inc(i,orgnext^.cnb);
  329. end
  330. else
  331. begin
  332. inc(i);
  333. if orgnext^.text=orgnext^.equivalent^.text then
  334. begin
  335. Writeln(FileName,'(',i,') ',orgnext^.enum,' not translated');
  336. If Is_interactive then
  337. GetTranslation(orgnext^.equivalent);
  338. if orgnext^.text=orgnext^.equivalent^.text then
  339. inc(ntcount);
  340. end;
  341. s2:=orgnext^.text;
  342. j:=pos('_',copy(s2,7,20)) + 6;
  343. s2:=upcase(copy(s2,1,j));
  344. s3:=orgnext^.equivalent^.text;
  345. j:=pos('_',copy(s3,7,20)) + 6;
  346. s3:=upcase(copy(s3,1,j));
  347. { that are the conditions in verbose unit }
  348. if (length(s3)<12) and (s2<>s3) then
  349. begin
  350. Writeln('Warning: different options for ',orgnext^.enum);
  351. Writeln('in ',orgFileName,' : ',s2);
  352. Writeln('in ',diffFileName,' : ',s3);
  353. If Is_interactive then
  354. begin
  355. Write('Use ',OrgFileName,' verbosity ? [y/n] ');
  356. Readln(s);
  357. if UpCase(s)<>'N' then
  358. orgnext^.equivalent^.text:=s2+copy(orgnext^.equivalent^.text,
  359. length(s3)+1,Length(orgnext^.equivalent^.text));
  360. end;
  361. end;
  362. Writeln(t,orgnext^.enum,'=',orgnext^.equivalent^.text);
  363. Dec(i); Inc(i,orgnext^.equivalent^.ctxt);
  364. if assigned(orgnext^.equivalent^.comment) and
  365. (strlen(orgnext^.equivalent^.comment)>0) then
  366. begin
  367. Write(t,orgnext^.equivalent^.comment);
  368. inc(i,orgnext^.equivalent^.cnb);
  369. end
  370. else if assigned(orgnext^.comment) and
  371. (strlen(orgnext^.comment)>0) then
  372. begin
  373. Writeln('Comment from ',OrgFileName,' for enum ',orgnext^.enum,' added');
  374. Write(t,orgnext^.comment);
  375. inc(i,orgnext^.cnb);
  376. end;
  377. end;
  378. orgnext:=orgnext^.filenext;
  379. end;
  380. while assigned(diffnext) do
  381. begin
  382. if not assigned(diffnext^.Equivalent) then
  383. begin
  384. { Skip removed enum in errore.msg}
  385. { maybe a renaming of an enum !}
  386. Writeln(diffnext^.enum,' commented out');
  387. Writeln(t,'%%% ',diffnext^.enum,'=',diffnext^.text);
  388. inc(i,diffnext^.ctxt);
  389. Write(t,diffnext^.comment);
  390. inc(i,diffnext^.cnb);
  391. end;
  392. diffnext:=diffnext^.filenext;
  393. end;
  394. Close(t);
  395. Close(t2);
  396. Close(t3);
  397. Writeln(ntcount,' not translated items found');
  398. end;
  399. begin
  400. ProcessOptions;
  401. ProcessFile(OrgFileName,orgroot,orgfirst);
  402. ProcessFile(DiffFileName,diffRoot,difffirst);
  403. PrintList('Org.lst',OrgRoot);
  404. PrintList('Diff.lst',DiffRoot);
  405. ShowDiff (OrgRoot,DiffRoot);
  406. WriteReorderedFile(NewFileName,orgfirst,difffirst);
  407. end.
  408. {
  409. $Log$
  410. Revision 1.4 2001-03-05 21:44:16 peter
  411. * small diffs from Sergey applied
  412. Revision 1.3 2001/02/09 23:04:56 peter
  413. * updated for new message file by Sergey Korshunoff
  414. Revision 1.2 2000/07/13 11:32:55 michael
  415. + removed logs
  416. }