1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gsicheck.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_transex3.hxx"
34 #include <tools/fsys.hxx>
35 #include <tools/stream.hxx>
36 #include <tools/list.hxx>
39 #include "tagtest.hxx"
40 #include "gsicheck.hxx"
42 #define MAX_GID_LID_LEN 250
44 /*****************************************************************************/
45 void PrintMessage( ByteString aType
, ByteString aMsg
, ByteString aPrefix
,
46 ByteString aContext
, BOOL bPrintContext
, ULONG nLine
, ByteString aUniqueId
= ByteString() )
47 /*****************************************************************************/
49 fprintf( stdout
, "%s %s, Line %lu", aType
.GetBuffer(), aPrefix
.GetBuffer(), nLine
);
50 if ( aUniqueId
.Len() )
51 fprintf( stdout
, ", UniqueID %s", aUniqueId
.GetBuffer() );
52 fprintf( stdout
, ": %s", aMsg
.GetBuffer() );
55 fprintf( stdout
, " \"%s\"", aContext
.GetBuffer() );
56 fprintf( stdout
, "\n" );
59 /*****************************************************************************/
60 void PrintError( ByteString aMsg
, ByteString aPrefix
,
61 ByteString aContext
, BOOL bPrintContext
, ULONG nLine
, ByteString aUniqueId
= ByteString() )
62 /*****************************************************************************/
64 PrintMessage( "Error:", aMsg
, aPrefix
, aContext
, bPrintContext
, nLine
, aUniqueId
);
67 BOOL
LanguageOK( ByteString aLang
)
72 if ( aLang
.IsNumericAscii() )
75 if ( aLang
.GetTokenCount( '-' ) == 1 )
76 return aLang
.IsAlphaAscii() && aLang
.IsLowerAscii();
77 else if ( aLang
.GetTokenCount( '-' ) == 2 )
79 ByteString
aTok0( aLang
.GetToken( 0, '-' ) );
80 ByteString
aTok1( aLang
.GetToken( 1, '-' ) );
81 return aTok0
.Len() && aTok0
.IsAlphaAscii() && aTok0
.IsLowerAscii()
82 && aTok1
.Len() && aTok1
.IsAlphaAscii() && aTok1
.IsUpperAscii()
83 && !aTok1
.EqualsIgnoreCaseAscii( aTok0
);
91 // class LazySvFileStream
95 class LazySvFileStream
: public SvFileStream
101 StreamMode eOpenMode
;
110 void SetOpenParams( const String
& rFileName
, StreamMode eOpenModeP
)
112 aFileName
= rFileName
;
113 eOpenMode
= eOpenModeP
;
119 void LazySvFileStream::LazyOpen()
123 Open( aFileName
, eOpenMode
);
126 fprintf( stderr
, "\nERROR: Could not open Output-File %s!\n\n", ByteString( aFileName
, RTL_TEXTENCODING_ASCII_US
).GetBuffer() );
138 /*****************************************************************************/
139 GSILine::GSILine( const ByteString
&rLine
, ULONG nLine
)
140 /*****************************************************************************/
141 : ByteString( rLine
)
142 , nLineNumber( nLine
)
146 if ( rLine
.GetTokenCount( '\t' ) == 15 )
148 aFormat
= FORMAT_SDF
;
149 aUniqId
= rLine
.GetToken( 0, '\t' );
150 aUniqId
.Append("/").Append( rLine
.GetToken( 1, '\t' ) ).Append("/").Append( rLine
.GetToken( 3, '\t' ) ).Append("/").Append( rLine
.GetToken( 4, '\t' ) ).Append("/").Append( rLine
.GetToken( 5, '\t' ) ).Append("/").Append( rLine
.GetToken( 6, '\t' ) ).Append("/").Append( rLine
.GetToken( 7, '\t' ) );
152 aLangId
= rLine
.GetToken( 9, '\t' );
153 aText
= rLine
.GetToken( 10, '\t' );
154 aQuickHelpText
= rLine
.GetToken( 12, '\t' );
155 aTitle
= rLine
.GetToken( 13, '\t' );
157 // do some more format checks here
158 if ( !rLine
.GetToken( 8, '\t' ).IsNumericAscii() )
160 PrintError( "The length field does not contain a number!", "Line format", rLine
.GetToken( 8, '\t' ), TRUE
, GetLineNumber(), GetUniqId() );
163 if ( !LanguageOK( aLangId
) )
165 PrintError( "The Language is invalid!", "Line format", aLangId
, TRUE
, GetLineNumber(), GetUniqId() );
168 // limit GID and LID to MAX_GID_LID_LEN chars each for database conformity, see #137575#
169 if ( rLine
.GetToken( 4, '\t' ).Len() > MAX_GID_LID_LEN
|| rLine
.GetToken( 5, '\t' ).Len() > MAX_GID_LID_LEN
)
171 PrintError( ByteString("GID and LID may only be ").Append( ByteString::CreateFromInt32(MAX_GID_LID_LEN
) ).Append( " chars long each!" ), "Line format", aLangId
, TRUE
, GetLineNumber(), GetUniqId() );
175 else // allow tabs in gsi files
177 aFormat
= FORMAT_GSI
;
178 ByteString
sTmp( rLine
);
179 USHORT nPos
= sTmp
.Search( "($$)" );
181 if ( nPos
!= STRING_NOTFOUND
)
183 aUniqId
= sTmp
.Copy( nStart
, nPos
- nStart
);
184 nStart
= nPos
+ 4; // + length of the delemiter
185 nPos
= sTmp
.Search( "($$)", nStart
);
187 if ( nPos
!= STRING_NOTFOUND
)
189 aLineType
= sTmp
.Copy( nStart
, nPos
- nStart
);
190 nStart
= nPos
+ 4; // + length of the delemiter
191 nPos
= sTmp
.Search( "($$)", nStart
);
192 aUniqId
.Append( "/" );
193 aUniqId
.Append( aLineType
);
195 if ( nPos
!= STRING_NOTFOUND
)
197 aLangId
= sTmp
.Copy( nStart
, nPos
- nStart
);
198 nStart
= nPos
+ 4; // + length of the delemiter
199 nPos
= sTmp
.Search( "($$)", nStart
);
201 if ( nPos
!= STRING_NOTFOUND
)
203 // ByteString aStatus = sTmp.Copy( nStart, nPos - nStart ); // ext int ...
204 nStart
= nPos
+ 4; // + length of the delemiter
206 if ( nPos
!= STRING_NOTFOUND
)
207 aText
= sTmp
.Copy( nStart
);
209 aFormat
= FORMAT_UNKNOWN
;
212 if ( FORMAT_UNKNOWN
== GetLineFormat() )
216 /*****************************************************************************/
217 void GSILine::NotOK()
218 /*****************************************************************************/
223 /*****************************************************************************/
224 void GSILine::ReassembleLine()
225 /*****************************************************************************/
227 ByteString aReassemble
;
228 if ( GetLineFormat() == FORMAT_SDF
)
231 for ( i
= 0 ; i
< 10 ; i
++ )
233 aReassemble
.Append( GetToken( i
, '\t' ) );
234 aReassemble
.Append( "\t" );
236 aReassemble
.Append( aText
);
237 aReassemble
.Append( "\t" );
238 aReassemble
.Append( GetToken( 11, '\t' ) ); // should be empty but there are some places in sc. Not reflected to sources!!
239 aReassemble
.Append( "\t" );
240 aReassemble
.Append( aQuickHelpText
);
241 aReassemble
.Append( "\t" );
242 aReassemble
.Append( aTitle
);
243 for ( i
= 14 ; i
< 15 ; i
++ )
245 aReassemble
.Append( "\t" );
246 aReassemble
.Append( GetToken( i
, '\t' ) );
248 *(ByteString
*)this = aReassemble
;
250 else if ( GetLineFormat() == FORMAT_GSI
)
252 USHORT nPos
= Search( "($$)" );
254 if ( nPos
!= STRING_NOTFOUND
)
256 nStart
= nPos
+ 4; // + length of the delemiter
257 nPos
= Search( "($$)", nStart
);
259 if ( nPos
!= STRING_NOTFOUND
)
261 nStart
= nPos
+ 4; // + length of the delemiter
262 nPos
= Search( "($$)", nStart
);
264 if ( nPos
!= STRING_NOTFOUND
)
266 nStart
= nPos
+ 4; // + length of the delemiter
267 nPos
= Search( "($$)", nStart
);
269 if ( nPos
!= STRING_NOTFOUND
)
271 nStart
= nPos
+ 4; // + length of the delemiter
273 if ( nPos
!= STRING_NOTFOUND
)
275 aReassemble
= Copy( 0, nStart
);
276 aReassemble
+= aText
;
277 *(ByteString
*)this = aReassemble
;
280 PrintError( "Cannot reassemble GSI line (internal Error).", "Line format", "", FALSE
, GetLineNumber(), GetUniqId() );
283 PrintError( "Cannot reassemble line of unknown type (internal Error).", "Line format", "", FALSE
, GetLineNumber(), GetUniqId() );
289 /*****************************************************************************/
290 GSIBlock::GSIBlock( BOOL PbPrintContext
, BOOL bSource
, BOOL bTrans
, BOOL bRef
, BOOL bAllowKID
, BOOL bAllowSusp
)
291 /*****************************************************************************/
292 : pSourceLine( NULL
)
293 , pReferenceLine( NULL
)
294 , bPrintContext( PbPrintContext
)
295 , bCheckSourceLang( bSource
)
296 , bCheckTranslationLang( bTrans
)
298 , bAllowKeyIDs( bAllowKID
)
299 , bAllowSuspicious( bAllowSusp
)
300 , bHasBlockError( FALSE
)
304 /*****************************************************************************/
305 GSIBlock::~GSIBlock()
306 /*****************************************************************************/
309 delete pReferenceLine
;
311 for ( ULONG i
= 0; i
< Count(); i
++ )
312 delete ( GetObject( i
));
315 /*****************************************************************************/
316 void GSIBlock::InsertLine( GSILine
* pLine
, ByteString aSourceLang
)
317 /*****************************************************************************/
319 if ( pLine
->GetLanguageId().Equals( aSourceLang
) )
323 PrintError( "Source Language entry double. Treating as Translation.", "File format", "", pLine
->GetLineNumber(), pLine
->GetUniqId() );
324 bHasBlockError
= TRUE
;
325 pSourceLine
->NotOK();
336 if ( aSourceLang
.Len() ) // only check blockstructure if source lang is given
338 while ( nPos
< Count() )
340 if ( GetObject( nPos
)->GetLanguageId().Equals( pLine
->GetLanguageId() ) )
342 PrintError( "Translation Language entry double. Checking both.", "File format", "", pLine
->GetLineNumber(), pLine
->GetUniqId() );
343 bHasBlockError
= TRUE
;
344 GetObject( nPos
)->NotOK();
350 Insert( pLine
, LIST_APPEND
);
353 /*****************************************************************************/
354 void GSIBlock::SetReferenceLine( GSILine
* pLine
)
355 /*****************************************************************************/
357 pReferenceLine
= pLine
;
360 /*****************************************************************************/
361 void GSIBlock::PrintMessage( ByteString aType
, ByteString aMsg
, ByteString aPrefix
,
362 ByteString aContext
, ULONG nLine
, ByteString aUniqueId
)
363 /*****************************************************************************/
365 ::PrintMessage( aType
, aMsg
, aPrefix
, aContext
, bPrintContext
, nLine
, aUniqueId
);
368 /*****************************************************************************/
369 void GSIBlock::PrintError( ByteString aMsg
, ByteString aPrefix
,
370 ByteString aContext
, ULONG nLine
, ByteString aUniqueId
)
371 /*****************************************************************************/
373 PrintMessage( "Error:", aMsg
, aPrefix
, aContext
, nLine
, aUniqueId
);
376 /*****************************************************************************/
377 void GSIBlock::PrintList( ParserMessageList
*pList
, ByteString aPrefix
,
379 /*****************************************************************************/
382 for ( i
= 0 ; i
< pList
->Count() ; i
++ )
384 ParserMessage
*pMsg
= pList
->GetObject( i
);
388 if ( pMsg
->GetTagBegin() == STRING_NOTFOUND
)
389 aContext
= pLine
->GetText().Copy( 0, 300 );
391 aContext
= pLine
->Copy( pMsg
->GetTagBegin()-150, 300 );
392 aContext
.EraseTrailingChars(' ');
393 aContext
.EraseLeadingChars(' ');
396 PrintMessage( pMsg
->Prefix(), pMsg
->GetErrorText(), aPrefix
, aContext
, pLine
->GetLineNumber(), pLine
->GetUniqId() );
400 /*****************************************************************************/
401 BOOL
GSIBlock::IsUTF8( const ByteString
&aTestee
, BOOL bFixTags
, USHORT
&nErrorPos
, ByteString
&aErrorMsg
, BOOL
&bHasBeenFixed
, ByteString
&aFixed
) const
402 /*****************************************************************************/
404 String
aUTF8Tester( aTestee
, RTL_TEXTENCODING_UTF8
);
405 if ( STRING_MATCH
!= (nErrorPos
= ByteString( aUTF8Tester
, RTL_TEXTENCODING_UTF8
).Match( aTestee
)) )
407 aUTF8Tester
= String( aTestee
.GetBuffer(), nErrorPos
, RTL_TEXTENCODING_UTF8
);
408 nErrorPos
= aUTF8Tester
.Len();
409 aErrorMsg
= ByteString( "UTF8 Encoding seems to be broken" );
413 nErrorPos
= aUTF8Tester
.SearchChar( String::CreateFromAscii( "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f"
414 "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f" ).GetBuffer() );
415 if ( nErrorPos
!= STRING_NOTFOUND
)
417 aErrorMsg
= ByteString( "String contains illegal character" );
423 bHasBeenFixed
= FALSE
;
429 BOOL bIsKeyID
= FALSE
;
431 ByteString
aID( aTestee
);
434 if ( aTestee
.Equals( "{&", 0, 2 ) )
435 { // check for strings from instset_native like "{&Tahoma8}335795.Installation Wiza ..."
436 USHORT nTagEnd
= aTestee
.Search( '}' );
437 if ( nTagEnd
!= STRING_NOTFOUND
)
440 aFixed
= aTestee
.Copy( 0, nTagEnd
+1 );
441 nErrorPos
= nTagEnd
+1;
442 aID
= aTestee
.Copy( nTagEnd
+1 );
443 nAfterID
= nTagEnd
+1;
447 ByteString
aDelimiter( (String
)String( sal_Unicode(0x2016) ), RTL_TEXTENCODING_UTF8
);
449 if ( aID
.Equals( aDelimiter
, 6, aDelimiter
.Len() ) )
450 { // New KeyId 6 Letters, digits and spechial chars followed by delimiter
453 aID
= aID
.Copy( 0, 6 );
455 nAfterID
= nAfterID
+ aDelimiter
.Len();
457 else if ( ( aID
.GetChar(6) == '*' ) && aID
.Equals( aDelimiter
, 7, aDelimiter
.Len() ) )
458 { // New KeyId 6 Letters, digits and spechial chars followed by '*delimiter' to indicate translation in progress
461 aID
= aID
.Copy( 0, 6 );
463 nAfterID
= nAfterID
+ aDelimiter
.Len();
465 else if ( aID
.GetTokenCount( '.' ) > 1 )
466 { // test for old KeyIDs 5 to 6 digits followed by a dot '44373.'
469 aID
= aID
.GetToken( 0, '.' );
470 nAfterID
= nAfterID
+ aID
.Len();
479 if ( aID
.Len() == 6 )
482 ByteString
aDigits("0123456789abcdefghijklmnopqrstuvwxyz+-<=>");
483 for ( USHORT i
=0 ; i
< aID
.Len() ;i
++ )
485 if ( aDigits
.Search( aID
.GetChar(i
) ) == STRING_NOTFOUND
)
492 if ( aID
.Len() > 0 && aID
.GetChar(aID
.Len()-1) == '*' )
493 aID
.Erase( aID
.Len()-1 );
495 if ( aID
.IsNumericAscii() && aID
.Len() >= 5 )
501 aErrorMsg
= ByteString( "String contains KeyID" );
504 aFixed
+= aTestee
.Copy( nAfterID
);
505 bHasBeenFixed
= TRUE
;
506 aErrorMsg
= ByteString( "FIXED String containing KeyID" );
509 aErrorMsg
= ByteString( "String contains KeyID" );
517 /*****************************************************************************/
518 BOOL
GSIBlock::TestUTF8( GSILine
* pTestee
, BOOL bFixTags
)
519 /*****************************************************************************/
521 USHORT nErrorPos
= 0;
522 ByteString aErrorMsg
;
525 BOOL bHasBeenFixed
= FALSE
;
526 if ( !IsUTF8( pTestee
->GetText(), bFixTags
, nErrorPos
, aErrorMsg
, bHasBeenFixed
, aFixed
) )
528 ByteString
aContext( pTestee
->GetText().Copy( nErrorPos
, 20 ) );
529 PrintError( aErrorMsg
.Append(" in Text at Position " ).Append( ByteString::CreateFromInt32( nErrorPos
) ), "Text format", aContext
, pTestee
->GetLineNumber(), pTestee
->GetUniqId() );
533 pTestee
->SetText( aFixed
);
537 if ( !IsUTF8( pTestee
->GetQuickHelpText(), bFixTags
, nErrorPos
, aErrorMsg
, bHasBeenFixed
, aFixed
) )
539 ByteString
aContext( pTestee
->GetQuickHelpText().Copy( nErrorPos
, 20 ) );
540 PrintError( aErrorMsg
.Append(" in QuickHelpText at Position " ).Append( ByteString::CreateFromInt32( nErrorPos
) ), "Text format", aContext
, pTestee
->GetLineNumber(), pTestee
->GetUniqId() );
544 pTestee
->SetQuickHelpText( aFixed
);
548 if ( !IsUTF8( pTestee
->GetTitle(), bFixTags
, nErrorPos
, aErrorMsg
, bHasBeenFixed
, aFixed
) )
550 ByteString
aContext( pTestee
->GetTitle().Copy( nErrorPos
, 20 ) );
551 PrintError( aErrorMsg
.Append(" in Title at Position " ).Append( ByteString::CreateFromInt32( nErrorPos
) ), "Text format", aContext
, pTestee
->GetLineNumber(), pTestee
->GetUniqId() );
555 pTestee
->SetTitle( aFixed
);
565 /*****************************************************************************/
566 BOOL
GSIBlock::HasSuspiciousChars( GSILine
* pTestee
, GSILine
* pSource
)
567 /*****************************************************************************/
570 if ( !bAllowSuspicious
&& ( nPos
= pTestee
->GetText().Search("??")) != STRING_NOTFOUND
)
571 if ( pSource
->GetText().Search("??") == STRING_NOTFOUND
)
573 String aUTF8Tester
= String( pTestee
->GetText(), 0, nPos
, RTL_TEXTENCODING_UTF8
);
574 USHORT nErrorPos
= aUTF8Tester
.Len();
575 ByteString
aContext( pTestee
->GetText().Copy( nPos
, 20 ) );
576 PrintError( ByteString("Found double questionmark in translation only. Looks like an encoding problem at Position " ).Append( ByteString::CreateFromInt32( nErrorPos
) ), "Text format", aContext
, pTestee
->GetLineNumber(), pTestee
->GetUniqId() );
585 /*****************************************************************************/
586 BOOL
GSIBlock::CheckSyntax( ULONG nLine
, BOOL bRequireSourceLine
, BOOL bFixTags
)
587 /*****************************************************************************/
589 static LingTest aTester
;
590 BOOL bHasError
= FALSE
;
594 if ( bRequireSourceLine
)
596 PrintError( "No source language entry defined!", "File format", "", nLine
);
597 bHasBlockError
= TRUE
;
602 aTester
.CheckReference( pSourceLine
);
603 if ( pSourceLine
->HasMessages() )
605 PrintList( pSourceLine
->GetMessageList(), "ReferenceString", pSourceLine
);
606 pSourceLine
->NotOK();
612 if ( !pReferenceLine
)
616 pSource
= pSourceLine
;
618 pSource
= GetObject( 0 ); // get some other line
620 PrintError( "No reference line found. Entry is new in source file", "File format", "", pSource
->GetLineNumber(), pSource
->GetUniqId() );
622 PrintError( "No reference line found. Entry is new in source file", "File format", "", nLine
);
623 bHasBlockError
= TRUE
;
627 if ( pSourceLine
&& !pSourceLine
->Equals( *pReferenceLine
) )
629 xub_StrLen nPos
= pSourceLine
->Match( *pReferenceLine
);
630 ByteString
aContext( pReferenceLine
->Copy( nPos
- 5, 15) );
631 aContext
.Append( "\" --> \"" ).Append( pSourceLine
->Copy( nPos
- 5, 15) );
632 PrintError( "Source Language Entry has changed.", "File format", aContext
, pSourceLine
->GetLineNumber(), pSourceLine
->GetUniqId() );
633 pSourceLine
->NotOK();
640 bHasError
|= !TestUTF8( pSourceLine
, bFixTags
);
643 for ( i
= 0; i
< Count(); i
++ )
645 aTester
.CheckTestee( GetObject( i
), pSourceLine
!= NULL
, bFixTags
);
646 if ( GetObject( i
)->HasMessages() || aTester
.HasCompareWarnings() )
648 if ( GetObject( i
)->HasMessages() || aTester
.GetCompareWarnings().HasErrors() )
649 GetObject( i
)->NotOK();
651 PrintList( GetObject( i
)->GetMessageList(), "Translation", GetObject( i
) );
652 PrintList( &(aTester
.GetCompareWarnings()), "Translation Tag Missmatch", GetObject( i
) );
654 bHasError
|= !TestUTF8( GetObject( i
), bFixTags
);
656 bHasError
|= HasSuspiciousChars( GetObject( i
), pSourceLine
);
659 return bHasError
|| bHasBlockError
;
662 void GSIBlock::WriteError( LazySvFileStream
&aErrOut
, BOOL bRequireSourceLine
)
664 if ( pSourceLine
&& pSourceLine
->IsOK() && bCheckSourceLang
&& !bHasBlockError
)
667 BOOL bHasError
= FALSE
;
668 BOOL bCopyAll
= ( !pSourceLine
&& bRequireSourceLine
) || ( pSourceLine
&& !pSourceLine
->IsOK() && !bCheckTranslationLang
) || bHasBlockError
;
670 for ( i
= 0; i
< Count(); i
++ )
672 if ( !GetObject( i
)->IsOK() || bCopyAll
)
676 aErrOut
.WriteLine( *GetObject( i
) );
680 if ( pSourceLine
&& ( bHasError
|| !pSourceLine
->IsOK() ) && !( !bHasError
&& bCheckTranslationLang
) )
683 aErrOut
.WriteLine( *pSourceLine
);
687 void GSIBlock::WriteCorrect( LazySvFileStream
&aOkOut
, BOOL bRequireSourceLine
)
689 if ( ( !pSourceLine
&& bRequireSourceLine
) || ( pSourceLine
&& !pSourceLine
->IsOK() && !bCheckTranslationLang
) )
694 for ( i
= 0; i
< Count(); i
++ )
696 if ( ( GetObject( i
)->IsOK() || bCheckSourceLang
) && !bHasBlockError
)
700 aOkOut
.WriteLine( *GetObject( i
) );
704 if ( ( pSourceLine
&& pSourceLine
->IsOK() && ( Count() || !bCheckTranslationLang
) ) || ( bHasOK
&& bCheckTranslationLang
) )
707 aOkOut
.WriteLine( *pSourceLine
);
711 void GSIBlock::WriteFixed( LazySvFileStream
&aFixOut
, BOOL
/*bRequireSourceLine*/ )
713 if ( pSourceLine
&& !pSourceLine
->IsFixed() && bCheckSourceLang
)
716 BOOL bHasFixes
= FALSE
;
718 for ( i
= 0; i
< Count(); i
++ )
720 if ( GetObject( i
)->IsFixed() )
724 aFixOut
.WriteLine( *GetObject( i
) );
728 if ( pSourceLine
&& ( bHasFixes
|| pSourceLine
->IsFixed() ) )
731 aFixOut
.WriteLine( *pSourceLine
);
736 /*****************************************************************************/
737 /*****************************************************************************/
738 /*****************************************************************************/
739 /*****************************************************************************/
740 /*****************************************************************************/
741 /*****************************************************************************/
742 /*****************************************************************************/
744 /*****************************************************************************/
746 /*****************************************************************************/
748 fprintf( stdout
, "\n" );
749 fprintf( stdout
, "gsicheck Version 1.9.0 (c)1999 - 2006 by SUN Microsystems\n" );
750 fprintf( stdout
, "=========================================================\n" );
751 fprintf( stdout
, "\n" );
752 fprintf( stdout
, "gsicheck checks the syntax of tags in GSI-Files and SDF-Files\n" );
753 fprintf( stdout
, " checks for inconsistencies and malicious UTF8 encoding\n" );
754 fprintf( stdout
, " checks tags in Online Help\n" );
755 fprintf( stdout
, " checks for *new* KeyIDs and relax GID/LID length to %s\n", ByteString::CreateFromInt32(MAX_GID_LID_LEN
).GetBuffer() );
756 fprintf( stdout
, "\n" );
757 fprintf( stdout
, "Syntax: gsicheck [ -c ] [-f] [ -we ] [ -wef ErrorFilename ] [ -wc ]\n" );
758 fprintf( stdout
, " [ -wcf CorrectFilename ] [ -s | -t ] [ -l LanguageID ]\n" );
759 fprintf( stdout
, " [ -r ReferenceFile ] filename\n" );
760 fprintf( stdout
, "\n" );
761 fprintf( stdout
, "-c Add context to error message (Print the line containing the error)\n" );
762 fprintf( stdout
, "-f try to fix errors. See also -wf -wff \n" );
763 fprintf( stdout
, "-wf Write File containing all fixed parts\n" );
764 fprintf( stdout
, "-wff Same as above but give own filename\n" );
765 fprintf( stdout
, "-we Write File containing all errors\n" );
766 fprintf( stdout
, "-wef Same as above but give own filename\n" );
767 fprintf( stdout
, "-wc Write File containing all correct parts\n" );
768 fprintf( stdout
, "-wcf Same as above but give own filename\n" );
769 fprintf( stdout
, "-s Check only source language. Should be used before handing out to vendor.\n" );
770 fprintf( stdout
, "-t Check only Translation language(s). Should be used before merging.\n" );
771 fprintf( stdout
, "-k Allow KeyIDs to be present in strings\n" );
772 fprintf( stdout
, "-e disable encoding checks. E.g.: double questionmark \'??\' which may be the\n" );
773 fprintf( stdout
, " result of false conversions\n" );
774 fprintf( stdout
, "-l ISO Languagecode or numerical 2 digits Identifier of the source language.\n" );
775 fprintf( stdout
, " Default is en-US. Use \"\" (empty string) or 'none'\n" );
776 fprintf( stdout
, " to disable source language dependent checks\n" );
777 fprintf( stdout
, "-r Reference filename to check that source language entries\n" );
778 fprintf( stdout
, " have not been changed\n" );
779 fprintf( stdout
, "\n" );
782 /*****************************************************************************/
783 #if defined(UNX) || defined(OS2)
784 int main( int argc
, char *argv
[] )
786 int _cdecl
main( int argc
, char *argv
[] )
788 /*****************************************************************************/
792 BOOL bPrintContext
= FALSE
;
793 BOOL bCheckSourceLang
= FALSE
;
794 BOOL bCheckTranslationLang
= FALSE
;
795 BOOL bWriteError
= FALSE
;
796 BOOL bWriteCorrect
= FALSE
;
797 BOOL bWriteFixed
= FALSE
;
798 BOOL bFixTags
= FALSE
;
799 BOOL bAllowKID
= FALSE
;
800 BOOL bAllowSuspicious
= FALSE
;
801 String aErrorFilename
;
802 String aCorrectFilename
;
803 String aFixedFilename
;
804 BOOL bFileHasError
= FALSE
;
805 ByteString
aSourceLang( "en-US" ); // English is default
806 ByteString aFilename
;
807 ByteString aReferenceFilename
;
808 BOOL bReferenceFile
= FALSE
;
809 for ( USHORT i
= 1 ; i
< argc
; i
++ )
811 if ( *argv
[ i
] == '-' )
813 switch (*(argv
[ i
]+1))
815 case 'c':bPrintContext
= TRUE
;
819 if ( (*(argv
[ i
]+2)) == 'e' )
821 if ( (*(argv
[ i
]+3)) == 'f' )
824 aErrorFilename
= String( argv
[ i
+1 ], RTL_TEXTENCODING_ASCII_US
);
830 fprintf( stderr
, "\nERROR: Switch %s requires parameter!\n\n", argv
[ i
] );
836 else if ( (*(argv
[ i
]+2)) == 'c' )
837 if ( (*(argv
[ i
]+3)) == 'f' )
840 aCorrectFilename
= String( argv
[ i
+1 ], RTL_TEXTENCODING_ASCII_US
);
841 bWriteCorrect
= TRUE
;
846 fprintf( stderr
, "\nERROR: Switch %s requires parameter!\n\n", argv
[ i
] );
850 bWriteCorrect
= TRUE
;
851 else if ( (*(argv
[ i
]+2)) == 'f' )
852 if ( (*(argv
[ i
]+3)) == 'f' )
855 aFixedFilename
= String( argv
[ i
+1 ], RTL_TEXTENCODING_ASCII_US
);
862 fprintf( stderr
, "\nERROR: Switch %s requires parameter!\n\n", argv
[ i
] );
872 fprintf( stderr
, "\nERROR: Unknown Switch %s!\n\n", argv
[ i
] );
877 case 's':bCheckSourceLang
= TRUE
;
879 case 't':bCheckTranslationLang
= TRUE
;
885 aSourceLang
= ByteString( argv
[ i
+1 ] );
886 if ( aSourceLang
.EqualsIgnoreCaseAscii( "none" ) )
892 fprintf( stderr
, "\nERROR: Switch %s requires parameter!\n\n", argv
[ i
] );
901 aReferenceFilename
= argv
[ i
+1 ];
902 bReferenceFile
= TRUE
;
907 fprintf( stderr
, "\nERROR: Switch %s requires parameter!\n\n", argv
[ i
] );
924 bAllowSuspicious
= TRUE
;
928 fprintf( stderr
, "\nERROR: Unknown Switch %s!\n\n", argv
[ i
] );
934 if ( !aFilename
.Len())
935 aFilename
= ByteString( argv
[ i
] );
938 fprintf( stderr
, "\nERROR: Only one filename may be specified!\n\n");
945 if ( !aFilename
.Len() || bError
)
951 if ( aSourceLang
.Len() && !LanguageOK( aSourceLang
) )
953 fprintf( stderr
, "\nERROR: The Language '%s' is invalid!\n\n", aSourceLang
.GetBuffer() );
958 if ( bCheckSourceLang
&& bCheckTranslationLang
)
960 fprintf( stderr
, "\nERROR: The Options -s and -t are mutually exclusive.\nUse only one of them.\n\n" );
967 DirEntry aSource
= DirEntry( String( aFilename
, RTL_TEXTENCODING_ASCII_US
));
968 if ( !aSource
.Exists()) {
969 fprintf( stderr
, "\nERROR: GSI-File %s not found!\n\n", aFilename
.GetBuffer() );
973 SvFileStream
aGSI( String( aFilename
, RTL_TEXTENCODING_ASCII_US
), STREAM_STD_READ
);
974 if ( !aGSI
.IsOpen()) {
975 fprintf( stderr
, "\nERROR: Could not open GSI-File %s!\n\n", aFilename
.GetBuffer() );
979 SvFileStream aReferenceGSI
;
980 if ( bReferenceFile
)
982 DirEntry aReferenceSource
= DirEntry( String( aReferenceFilename
, RTL_TEXTENCODING_ASCII_US
));
983 if ( !aReferenceSource
.Exists()) {
984 fprintf( stderr
, "\nERROR: GSI-File %s not found!\n\n", aFilename
.GetBuffer() );
988 aReferenceGSI
.Open( String( aReferenceFilename
, RTL_TEXTENCODING_ASCII_US
), STREAM_STD_READ
);
989 if ( !aReferenceGSI
.IsOpen()) {
990 fprintf( stderr
, "\nERROR: Could not open Input-File %s!\n\n", aFilename
.GetBuffer() );
995 LazySvFileStream aOkOut
;
996 String aBaseName
= aSource
.GetBase();
999 if ( !aCorrectFilename
.Len() )
1001 String
sTmpBase( aBaseName
);
1002 sTmpBase
+= String( "_ok", RTL_TEXTENCODING_ASCII_US
);
1003 aSource
.SetBase( sTmpBase
);
1004 aCorrectFilename
= aSource
.GetFull();
1006 aOkOut
.SetOpenParams( aCorrectFilename
, STREAM_STD_WRITE
| STREAM_TRUNC
);
1009 LazySvFileStream aErrOut
;
1012 if ( !aErrorFilename
.Len() )
1014 String
sTmpBase( aBaseName
);
1015 sTmpBase
+= String( "_err", RTL_TEXTENCODING_ASCII_US
);
1016 aSource
.SetBase( sTmpBase
);
1017 aErrorFilename
= aSource
.GetFull();
1019 aErrOut
.SetOpenParams( aErrorFilename
, STREAM_STD_WRITE
| STREAM_TRUNC
);
1022 LazySvFileStream aFixOut
;
1025 if ( !aFixedFilename
.Len() )
1027 String
sTmpBase( aBaseName
);
1028 sTmpBase
+= String( "_fix", RTL_TEXTENCODING_ASCII_US
);
1029 aSource
.SetBase( sTmpBase
);
1030 aFixedFilename
= aSource
.GetFull();
1032 aFixOut
.SetOpenParams( aFixedFilename
, STREAM_STD_WRITE
| STREAM_TRUNC
);
1036 ByteString sReferenceLine
;
1037 GSILine
* pReferenceLine
= NULL
;
1038 ByteString
aOldReferenceId("No Valid ID"); // just set to something which can never be an ID
1039 ULONG nReferenceLine
= 0;
1041 ByteString sGSILine
;
1042 GSILine
* pGSILine
= NULL
;
1043 ByteString
aOldId("No Valid ID"); // just set to something which can never be an ID
1044 GSIBlock
*pBlock
= NULL
;
1047 while ( !aGSI
.IsEof() )
1049 aGSI
.ReadLine( sGSILine
);
1051 pGSILine
= new GSILine( sGSILine
, nLine
);
1052 BOOL bDelete
= TRUE
;
1055 if ( pGSILine
->Len() )
1057 if ( FORMAT_UNKNOWN
== pGSILine
->GetLineFormat() )
1059 PrintError( "Format of line is unknown. Ignoring!", "Line format", pGSILine
->Copy( 0,40 ), bPrintContext
, pGSILine
->GetLineNumber() );
1063 bFileHasError
= TRUE
;
1065 aErrOut
.WriteLine( *pGSILine
);
1068 else if ( pGSILine
->GetLineType().EqualsIgnoreCaseAscii("res-comment") )
1069 { // ignore comment lines, but write them to Correct Items File
1070 if ( bWriteCorrect
)
1073 aOkOut
.WriteLine( *pGSILine
);
1078 ByteString aId
= pGSILine
->GetUniqId();
1079 if ( aId
!= aOldId
)
1083 bFileHasError
|= pBlock
->CheckSyntax( nLine
, aSourceLang
.Len() != 0, bFixTags
);
1086 pBlock
->WriteError( aErrOut
, aSourceLang
.Len() != 0 );
1087 if ( bWriteCorrect
)
1088 pBlock
->WriteCorrect( aOkOut
, aSourceLang
.Len() != 0 );
1090 pBlock
->WriteFixed( aFixOut
, aSourceLang
.Len() != 0 );
1094 pBlock
= new GSIBlock( bPrintContext
, bCheckSourceLang
, bCheckTranslationLang
, bReferenceFile
, bAllowKID
, bAllowSuspicious
);
1099 // find corresponding line in reference file
1100 if ( bReferenceFile
)
1102 BOOL bContinueSearching
= TRUE
;
1103 while ( ( !aReferenceGSI
.IsEof() || pReferenceLine
) && bContinueSearching
)
1105 if ( !pReferenceLine
)
1107 aReferenceGSI
.ReadLine( sReferenceLine
);
1109 pReferenceLine
= new GSILine( sReferenceLine
, nReferenceLine
);
1111 if ( pReferenceLine
->GetLineFormat() != FORMAT_UNKNOWN
)
1113 if ( pReferenceLine
->GetUniqId() == aId
&& pReferenceLine
->GetLanguageId().Equals( aSourceLang
) )
1115 pBlock
->SetReferenceLine( pReferenceLine
);
1116 pReferenceLine
= NULL
;
1118 else if ( pReferenceLine
->GetUniqId() > aId
)
1120 // if ( pGSILine->GetLanguageId() == aSourceLang )
1121 // PrintError( "No reference line found. Entry is new in source file", "File format", "", bPrintContext, pGSILine->GetLineNumber(), aId );
1122 bContinueSearching
= FALSE
;
1126 if ( pReferenceLine
->GetUniqId() < aId
&& pReferenceLine
->GetLanguageId().Equals( aSourceLang
) )
1127 PrintError( "No Entry in source file found. Entry has been removed from source file", "File format", "", bPrintContext
, pGSILine
->GetLineNumber(), pReferenceLine
->GetUniqId() );
1128 delete pReferenceLine
;
1129 pReferenceLine
= NULL
;
1134 delete pReferenceLine
;
1135 pReferenceLine
= NULL
;
1143 pBlock
->InsertLine( pGSILine
, aSourceLang
);
1153 bFileHasError
|= pBlock
->CheckSyntax( nLine
, aSourceLang
.Len() != 0, bFixTags
);
1156 pBlock
->WriteError( aErrOut
, aSourceLang
.Len() != 0 );
1157 if ( bWriteCorrect
)
1158 pBlock
->WriteCorrect( aOkOut
, aSourceLang
.Len() != 0 );
1160 pBlock
->WriteFixed( aFixOut
, aSourceLang
.Len() != 0 );
1168 if ( bWriteCorrect
)
1173 if ( bFileHasError
)