msgdif.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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. s,s2,s3 : string;
  288. is_msg : boolean;
  289. nextdiffkept : pmsg;
  290. begin
  291. ntcount:=0;
  292. Assign(t,FileName);
  293. Rewrite(t);
  294. Writeln(t,'%%% Reordering of ',DiffFileName,' respective to ',OrgFileName);
  295. Writeln(t,'%%% Contains all comments from ',DiffFileName);
  296. Assign(t2,DiffFileName);
  297. Reset(t2);
  298. Assign(t3,OrgFileName);
  299. Reset(t3);
  300. i:=2;
  301. s:='';s3:='';
  302. nextdiffkept:=diffnext;
  303. while assigned(nextdiffkept) and (nextdiffkept^.equivalent=nil) do
  304. nextdiffkept:=nextdiffkept^.filenext;
  305. { First write the header of diff }
  306. repeat
  307. Readln(t2,s);
  308. is_msg:=(pos('=',s)>1) and (s[1]<>'%') and (s[1]<>'#');
  309. if not is_msg then
  310. begin
  311. Writeln(t,s);
  312. inc(i);
  313. end;
  314. until is_msg;
  315. { Write all messages in Org order }
  316. while assigned(orgnext) do
  317. begin
  318. if not assigned(orgnext^.equivalent) then
  319. begin
  320. { Insert a new error msg with the english comments }
  321. Writeln('New error ',orgnext^.enum,' added');
  322. If Is_interactive then
  323. GetTranslation(orgnext);
  324. Writeln(t,orgnext^.enum,'=',orgnext^.text);
  325. inc(i,orgnext^.ctxt);
  326. Write(t,orgnext^.comment);
  327. inc(i,orgnext^.cnb);
  328. end
  329. else
  330. begin
  331. inc(i);
  332. if orgnext^.text=orgnext^.equivalent^.text then
  333. begin
  334. Writeln(FileName,'(',i,') ',orgnext^.enum,' not translated');
  335. If Is_interactive then
  336. GetTranslation(orgnext^.equivalent);
  337. if orgnext^.text=orgnext^.equivalent^.text then
  338. inc(ntcount);
  339. end;
  340. s2:=orgnext^.text;
  341. s2:=upcase(copy(s2,1,pos('_',s2)));
  342. s3:=orgnext^.equivalent^.text;
  343. s3:=upcase(copy(s3,1,pos('_',s3)));
  344. { that are the conditions in verbose unit }
  345. if (length(s3)<5) and (s2<>s3) then
  346. begin
  347. Writeln('Warning: different options for ',orgnext^.enum);
  348. Writeln('in ',orgFileName,' : ',s2);
  349. Writeln('in ',diffFileName,' : ',s3);
  350. If Is_interactive then
  351. begin
  352. Write('Use ',OrgFileName,' verbosity ? [y/n] ');
  353. Readln(s);
  354. if UpCase(s)<>'N' then
  355. orgnext^.equivalent^.text:=s2+copy(orgnext^.equivalent^.text,
  356. length(s3)+1,Length(orgnext^.equivalent^.text));
  357. end;
  358. end;
  359. Writeln(t,orgnext^.enum,'=',orgnext^.equivalent^.text);
  360. Dec(i); Inc(i,orgnext^.equivalent^.ctxt);
  361. if assigned(orgnext^.equivalent^.comment) and
  362. (strlen(orgnext^.equivalent^.comment)>0) then
  363. begin
  364. Write(t,orgnext^.equivalent^.comment);
  365. inc(i,orgnext^.equivalent^.cnb);
  366. end
  367. else if assigned(orgnext^.comment) and
  368. (strlen(orgnext^.comment)>0) then
  369. begin
  370. Writeln('Comment from ',OrgFileName,' for enum ',orgnext^.enum,' added');
  371. Write(t,orgnext^.comment);
  372. inc(i,orgnext^.cnb);
  373. end;
  374. end;
  375. orgnext:=orgnext^.filenext;
  376. end;
  377. while assigned(diffnext) do
  378. begin
  379. if not assigned(diffnext^.Equivalent) then
  380. begin
  381. { Skip removed enum in errore.msg}
  382. { maybe a renaming of an enum !}
  383. Writeln(diffnext^.enum,' commented out');
  384. Writeln(t,'%%% ',diffnext^.enum,'=',diffnext^.text);
  385. inc(i,diffnext^.ctxt);
  386. Write(t,diffnext^.comment);
  387. inc(i,diffnext^.cnb);
  388. end;
  389. diffnext:=diffnext^.filenext;
  390. end;
  391. Close(t);
  392. Close(t2);
  393. Close(t3);
  394. Writeln(ntcount,' not translated items found');
  395. end;
  396. begin
  397. ProcessOptions;
  398. ProcessFile(OrgFileName,orgroot,orgfirst);
  399. ProcessFile(DiffFileName,diffRoot,difffirst);
  400. PrintList('Org.lst',OrgRoot);
  401. PrintList('Diff.lst',DiffRoot);
  402. ShowDiff (OrgRoot,DiffRoot);
  403. WriteReorderedFile(NewFileName,orgfirst,difffirst);
  404. end.
  405. {
  406. $Log$
  407. Revision 1.3 2001-02-09 23:04:56 peter
  408. * updated for new message file by Sergey Korshunoff
  409. Revision 1.2 2000/07/13 11:32:55 michael
  410. + removed logs
  411. }