| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 | {    This program is part of the Free Pascal run time library.    Copyright (c) 1998-2002 by Peter Vreman    Show the differences between two .msg files    See the file COPYING.FPC, included in this distribution,    for details about the copyright.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************}{ May be we need to compare a prefixes of option_help_pages too?  Currently this is not performed }Program messagedif;{$h+} {Huge strings}Uses  Strings;Type  TEnum = String;  TText = String;  PMsg = ^TMsg;  TMsg = Record     Line, ctxt, cnb : Longint;     enum : TEnum;     text : TText;     comment : pchar;     Next,Prev : PMsg;     FileNext,     Equivalent : PMsg;   end;Var  OrgFileName,DiffFileName : String;  OrgRoot,DiffRoot : PMsg;  OrgFirst,DiffFirst : PMsg;  Last : PMsg;const  NewFileName = 'new.msg';  Is_interactive : boolean = false;  Auto_verbosity : boolean = false;Procedure GetTranslation( p : PMsg);var   s : string;   i,j,k : longint;begin  i:=pos('_',p^.text);  if i>0 then    for j:=i+1 to Length(p^.text) do      if p^.text[j]='_' then        begin          i:=j;          break;        end;  if (i>0) and (i<=15) then      Writeln(P^.Enum,' type  "',copy(p^.text,1,i-1),'" "',copy(p^.text,i+1,255),'"')  else    Writeln(P^.enum,' "',p^.text,'"');  Writeln('Type translated error message in,');  Writeln('Press return to keep it unchanged, or "q" to finish interactive mode');  Readln(s);  if s='' then    exit;  if s='q' then    begin      Is_interactive:=false;      exit;    end;  j:=pos('_',s);  if j>0 then    for k:=j+1 to Length(s) do      if s[j]='_' then        begin          j:=k;          break;        end;  if (j>0) then    begin      if copy(p^.text,1,i)<>copy(s,1,j) then        Writeln('Warning : different verbosity !!');      p^.text:=s;    end  else    p^.text:=copy(p^.text,1,i)+s;end;Function NewMsg (Var RM : PMsg; L : Longint; Const E : TEnum;Const T : TText;C : pchar;NbLn,TxtLn : longint) : PMsg;Var  P,R : PMsg;begin  New(P);  with P^ do    begin    Line:=L;    Text:=T;    enum:=E;    comment:=c;    cnb:=NbLn;    ctxt:=TxtLn;    next:=Nil;    prev:=Nil;    filenext:=nil;    equivalent:=nil;    if assigned(last) then      last^.FileNext:=P;    last:=P;    end;  R:=RM;  While (R<>Nil) and (UpCase(R^.enum)>UpCase(P^.Enum)) do    begin      P^.Prev:=R;      R:=R^.next;    end;  if assigned(R) and (UpCase(R^.Enum)=UpCase(P^.Enum)) then    Writeln('Error ',R^.Enum,' duplicate');  P^.Next:=R;  If R<>Nil then    R^.Prev:=P;  If P^.Prev<>Nil then    P^.Prev^.Next:=P  else    RM:=P;  NewMsg:=P;end;Procedure PrintList(const name : string;R : PMsg);var  P : PMsg;  f : text;begin  P:=R;  Assign(f,name);  Rewrite(f);  while assigned(P) do    begin      Writeln(f,UpCase(P^.Enum));      P:=P^.Next;    end;  Close(f);end;Procedure Usage;begin  Writeln('Usage : msgdif [options] <org-file> <dif-file>');  Writeln('Options:');  Writeln('   -i    allow to enter translated messages interactively');  Writeln('   -y1   use <org-file> verbosity (do not query acknowledge)');  Writeln('');  Writeln('Generates "',NewFileName,'" that contain the messages from <dif-file>');  Writeln('with a new messages from <org-file>');  Writeln('');  Writeln('Example:');  Writeln('  msgdif errore.msg errorr.msg');  halt(1)end;Procedure ProcessOptions;var  i,count : longint;begin  Is_interactive:=false;  Auto_verbosity:=false;  count:=paramcount; i:=1;  while (count>0) and (Paramstr(i)[1]='-') do   case UpCase(Paramstr(i)[2]) of     'I': begin            Is_interactive:=true;            dec(count); Inc(i);          end;     'Y': case Paramstr(i)[3] of            '1': begin                   Auto_verbosity:=true;                   dec(count); Inc(i);                 end;          else            Writeln ('Error: unknown option ', Paramstr(i));            Usage;          end;   else     Writeln ('Error: unknown option ', Paramstr(i));     Usage;   end;  If Count<>2 then begin    Writeln ('Error: there must be exactly two message files');    Usage;  end;  OrgfileName:=Paramstr(i);  DiffFileName:=Paramstr(i+1);  if (OrgFileName=NewFileName) or (DiffFileName=NewFileName) then    begin      Writeln('The file names must be different from ',NewFileName);      Halt(1);    end;end;Procedure ProcessFile (FileName : String; Var Root,First : PMsg);Const    ArrayLength = 65500;Var F : Text;    S,prevS : String;    J,LineNo,Count,NbLn,TxtLn : Longint;    chararray : array[0..ArrayLength] of char;    currentindex : longint;    c : pchar;    multiline : boolean;begin  Assign(F,FileName);  Reset(F);  Write ('Processing: ',Filename,'...');  LineNo:=0;  NbLn:=0;  TxtLn:=0;  Count:=0;  currentindex:=0;  Root:=Nil;  First:=nil;  Last:=nil;  PrevS:='';  multiline:=false;  While not eof(f) do    begin    Readln(F,S);    Inc(LineNo);    If multiline then      begin        PrevS:=PrevS+#10+S; Inc(TxtLn);        if (Length(S)<>0) and (S[1]=']') then          multiline:=false;      end    else    if (length(S)>0) and Not (S[1] in ['%','#']) Then    begin      J:=Pos('=',S);      If j<1 then        writeln (Filename,'(',LineNo,') : Invalid entry')      else        begin        chararray[currentindex]:=#0;        c:=strnew(@chararray);        if PrevS<>'' then          NewMsg(Root,LineNo,Copy(PrevS,1,Pos('=',PrevS)-1),           Copy(PrevS,Pos('=',PrevS)+1,Length(PrevS)),c,NbLn,TxtLn)        else          StrDispose(c);        currentindex:=0;        NbLn:=0; TxtLn:=0;        PrevS:=S; Inc(TxtLn);        if S[j+7]='[' then multiline:=true;        if First=nil then          First:=Root;        Inc(Count);        end;      end    else      begin        if currentindex+length(s)+1>ArrayLength then          Writeln('Comment too long : over ',ArrayLength,' chars')        else          begin            strpcopy(@chararray[currentindex],s+#10);            inc(currentindex,length(s)+1);            inc(NbLn);          end;      end;    end;  chararray[currentindex]:=#0;  c:=strnew(@chararray);  if PrevS<>'' then    NewMsg(Root,LineNo,Copy(PrevS,1,Pos('=',PrevS)-1),     Copy(PrevS,Pos('=',PrevS)+1,Length(PrevS)),c,NbLn,TxtLn);  Writeln (' Done. Read ',LineNo,' lines, got ',Count,' constants.');  Close(f);end;Procedure ShowDiff (POrg,PDiff : PMsg);Var  count,orgcount,diffcount : longint;Procedure NotFound (Org : Boolean; P : PMsg);begin  With P^ do    If Org Then      Writeln ('Not found in ',DiffFileName,' : ',Enum,' ',OrgFileName,'(',Line,')')    else      Writeln ('Extra in ',DiffFileName,'(',line,') : ',enum);  if org then    inc(orgcount)  else    inc(diffcount);end;begin  orgcount:=0;  diffcount:=0;  count:=0;  While (Porg<>Nil) and (PDiff<>Nil) do    begin//    Writeln (POrg^.enum,'<=>',PDiff^.Enum);    If UpCase(Porg^.Enum)>UpCase(PDiff^.Enum) then      begin      NotFound (True,Porg);      POrg:=POrg^.Next      end    else If UpCase(POrg^.enum)=UpCase(PDiff^.Enum)  then      begin      inc(count);      POrg^.Equivalent:=PDiff;      PDiff^.Equivalent:=POrg;      POrg:=POrg^.Next;      PDiff:=PDiff^.Next;      end    else      begin      NotFound (False,PDiff);      PDiff:=PDiff^.Next      end;    end;   While POrg<>Nil do     begin     NotFound(True,Porg);     POrg:=pOrg^.Next;     end;   While PDiff<>Nil do     begin     NotFound(False,PDiff);     PDiff:=PDiff^.Next;     end;   Writeln(count,' messages found in common to both files');   Writeln(orgcount,' messages only in ',OrgFileName);   Writeln(diffcount,' messages only in ',DiffFileName);end;type TArgSet = set of 0..31;function MsgToSet(const Msg, FileName: string; var R: TArgSet): Boolean;  var    i, j,l, num : integer;    code : word;  begin    R:=[];    MsgToSet:=false;    for i:=1 to Length(Msg) do      if Msg[i]='$' then      begin        j:=i+1; l:=length(msg)+1;        while (j<l) and (Msg[j] in ['0'..'9']) do Inc(j);        if j > (i+1) then        begin          val(copy(Msg,i+1,j-i-1),num,code);          if num > high(TArgSet) then begin            WriteLn('Error in ', FileName,': ', Msg);            WriteLn(' number at position ', i);            WriteLn(' must be LE ', high(TArgSet));            Exit;          end;          R:=R+[num];        end;      end;      MsgToSet:=true;  end;procedure CheckParm(const s1, s2: string);  var    R1, R2: TArgSet;  begin    if MsgToSet(s1,OrgFileName, R1) <> true then Exit;    if MsgToSet(s2,DiffFileName,R2) <> true then Exit;    if R1<>R2 then begin      WriteLn('Error: set of arguments is different');      WriteLn(' ',s1);      WriteLn(' ',s2);    end;  end;procedure WriteReorderedFile(FileName : string;orgnext,diffnext : PMsg);  var t,t2,t3 : text;      i,ntcount : longint;      j : integer;      s,s2,s3 : string;      is_msg : boolean;      nextdiffkept : pmsg;  begin     ntcount:=0;     Assign(t,FileName);     Rewrite(t);     Writeln(t,'%%% Reordering of ',DiffFileName,' respective to ',OrgFileName);     Writeln(t,'%%% Contains all comments from ',DiffFileName);     Assign(t2,DiffFileName);     Reset(t2);     Assign(t3,OrgFileName);     Reset(t3);     i:=2;     s:='';s3:='';     nextdiffkept:=diffnext;     while assigned(nextdiffkept) and (nextdiffkept^.equivalent=nil) do       nextdiffkept:=nextdiffkept^.filenext;     { First write the header of diff }     repeat       Readln(t2,s);       is_msg:=(pos('=',s)>1) and (s[1]<>'%') and (s[1]<>'#');       if not is_msg then         begin           Writeln(t,s);           inc(i);         end;     until is_msg;     { Write all messages in Org order }     while assigned(orgnext) do       begin         if not assigned(orgnext^.equivalent) then           begin             { Insert a new error msg with the english comments }             Writeln('New error ',orgnext^.enum,' added');             If Is_interactive then               GetTranslation(orgnext);             Writeln(t,orgnext^.enum,'=',orgnext^.text);             inc(i,orgnext^.ctxt);             Write(t,orgnext^.comment);             inc(i,orgnext^.cnb);           end         else           begin             inc(i);             if orgnext^.text=orgnext^.equivalent^.text then               begin                 Writeln(FileName,'(',i,') ',orgnext^.enum,' not translated');                 If Is_interactive then                   GetTranslation(orgnext^.equivalent);                 if orgnext^.text=orgnext^.equivalent^.text then                   inc(ntcount);               end;             s2:=orgnext^.text;             j:=pos('_',copy(s2,7,20)) + 6;             s2:=upcase(copy(s2,1,j));             s3:=orgnext^.equivalent^.text;             j:=pos('_',copy(s3,7,20)) + 6;             s3:=upcase(copy(s3,1,j));             { that are the conditions in verbose unit }             if (length(s3)<12) and (s2<>s3) then               begin                 Writeln('Warning: different options for ',orgnext^.enum);                 Writeln(' ',orgnext^.text);                 Writeln(' ',orgnext^.equivalent^.text);                 s:='N';                 if Auto_verbosity then                   s:='Y'                 else                 If Is_interactive then                   begin                     Write('Use ',s2,' verbosity ? [y/n] ');                     Readln(s);                   end;                 if UpCase(s[1])='Y' then                   begin                     orgnext^.equivalent^.text:=s2+copy(orgnext^.equivalent^.text,                       length(s3)+1,Length(orgnext^.equivalent^.text));                     WriteLn(' Using ', s2);                   end;               end;             CheckParm(orgnext^.text, orgnext^.equivalent^.text);             Writeln(t,orgnext^.enum,'=',orgnext^.equivalent^.text);             Dec(i); Inc(i,orgnext^.equivalent^.ctxt);             if assigned(orgnext^.equivalent^.comment) and               (strlen(orgnext^.equivalent^.comment)>0) then             begin               Write(t,orgnext^.equivalent^.comment);               inc(i,orgnext^.equivalent^.cnb);             end             else if assigned(orgnext^.comment) and               (strlen(orgnext^.comment)>0) then               begin                 Writeln('Comment from ',OrgFileName,' for enum ',orgnext^.enum,' added');                 Write(t,orgnext^.comment);                 inc(i,orgnext^.cnb);               end;           end;         orgnext:=orgnext^.filenext;       end;     while assigned(diffnext) do       begin         if not assigned(diffnext^.Equivalent) then           begin              { Skip removed enum in errore.msg}              { maybe a renaming of an enum !}              Writeln(diffnext^.enum,' commented out');              Writeln(t,'%%% ',diffnext^.enum,'=',diffnext^.text);              inc(i,diffnext^.ctxt);              Write(t,diffnext^.comment);              inc(i,diffnext^.cnb);           end;         diffnext:=diffnext^.filenext;       end;     Close(t);     Close(t2);     Close(t3);     Writeln(ntcount,' not translated items found');  end;begin  ProcessOptions;  ProcessFile(OrgFileName,orgroot,orgfirst);  ProcessFile(DiffFileName,diffRoot,difffirst);  PrintList('org.lst',OrgRoot);  PrintList('diff.lst',DiffRoot);  ShowDiff (OrgRoot,DiffRoot);  WriteReorderedFile(NewFileName,orgfirst,difffirst);end.
 |