msgdif.pp 10 KB

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