1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
26 #include "boost/scoped_ptr.hpp"
33 #include <rtl/strbuf.hxx>
35 void yyerror( const char * );
36 void YYWarning( const char * );
40 MergeDataFile
* pMergeDataFile
= 0; //TODO
44 OString inputPathname
;
45 boost::scoped_ptr
< Export
> exporter
;
53 FILE * init(int argc
, char ** argv
) {
55 common::HandledArgs aArgs
;
56 if ( !common::handleArguments(argc
, argv
, aArgs
) )
58 common::writeUsage("transex3","*.src/*.hrc");
59 std::exit(EXIT_FAILURE
);
61 global::inputPathname
= aArgs
.m_sInputFile
;
63 FILE * pFile
= std::fopen(global::inputPathname
.getStr(), "r");
66 stderr
, "Error: Cannot open file \"%s\"\n",
67 global::inputPathname
.getStr());
68 std::exit(EXIT_FAILURE
);
71 if (aArgs
.m_bMergeMode
) {
72 global::exporter
.reset(
73 new Export(aArgs
.m_sMergeSrc
, aArgs
.m_sOutputFile
, aArgs
.m_sLanguage
));
75 global::exporter
.reset(new Export(aArgs
.m_sOutputFile
));
78 global::exporter
->Init();
83 int Parse( int nTyp
, const char *pTokenText
){
84 global::exporter
->Execute( nTyp
, pTokenText
);
88 global::exporter
->pParseQueue
->Close();
89 global::exporter
.reset();
90 // avoid nontrivial Export dtor being executed during exit
93 int WorkOnTokenSet( int nTyp
, char *pTokenText
)
96 global::exporter
->pParseQueue
->Push( QueueEntry( nTyp
, OString(pTokenText
) ) );
106 // set error at global instance of class Export
107 global::exporter
->SetError();
116 // get error at global instance of class Export
117 if (global::exporter
->GetError())
127 sal_Bool
ResData::SetId( const OString
& rId
, sal_uInt16 nLevel
)
129 if ( nLevel
> nIdLevel
)
134 if ( bChild
&& bChildWithText
)
136 OString
sError(RTL_CONSTASCII_STRINGPARAM("ResId after child definition"));
137 yyerror(sError
.getStr());
141 if ( sId
.getLength() > 255 )
143 YYWarning( "LocalId > 255 chars, truncating..." );
144 sId
= sId
.copy(0, 255).trim();
160 static sal_Int32
lcl_countOccurrences(const OString
& text
, char c
)
163 for (sal_Int32 i
= 0;; ++i
) {
164 i
= text
.indexOf(c
, i
);
175 Export::Export(const OString
&rOutput
)
177 bDefine( sal_False
),
178 bNextMustBeDefineEOL( sal_False
),
186 bReadOver( sal_False
),
187 bDontWriteOutput( sal_False
),
188 sFilename( global::inputPathname
),
189 sLanguages( OString() ),
190 pParseQueue( new ParserQueue( *this ) )
192 aOutput
.mPo
= new PoOfstream( rOutput
, PoOfstream::APP
);
193 if (!aOutput
.mPo
->isOpen()) {
194 fprintf(stderr
, "ERROR : Can't open file %s\n", rOutput
.getStr());
200 const OString
&rMergeSource
, const OString
&rOutput
,
201 const OString
&rLanguage
)
203 bDefine( sal_False
),
204 bNextMustBeDefineEOL( sal_False
),
210 bMergeMode( sal_True
),
211 sMergeSrc( rMergeSource
),
213 bReadOver( sal_False
),
214 bDontWriteOutput( sal_False
),
215 sFilename( global::inputPathname
),
216 sLanguages( rLanguage
),
217 pParseQueue( new ParserQueue( *this ) )
219 aOutput
.mSimple
= new std::ofstream();
220 aOutput
.mSimple
->open(rOutput
.getStr(), std::ios_base::out
| std::ios_base::trunc
);
225 // resets the internal status, used before parseing another file
227 bNextMustBeDefineEOL
= sal_False
;
230 m_sListLang
= OString();
232 for ( size_t i
= 0, n
= aResStack
.size(); i
< n
; ++i
)
233 delete aResStack
[ i
];
243 aOutput
.mSimple
->close();
244 delete aOutput
.mSimple
;
248 aOutput
.mPo
->close();
251 for ( size_t i
= 0, n
= aResStack
.size(); i
< n
; ++i
)
252 delete aResStack
[ i
];
256 if ( !pMergeDataFile
)
257 pMergeDataFile
= new MergeDataFile(sMergeSrc
, global::inputPathname
, false);
259 delete pMergeDataFile
;
263 int Export::Execute( int nToken
, const char * pToken
)
266 OString
sToken( pToken
);
267 OString
sOrig( sToken
);
268 sal_Bool bWriteToMerged
= bMergeMode
;
270 if ( nToken
== CONDITION
)
272 OString
sTestToken(pToken
);
273 sTestToken
= sTestToken
.replaceAll("\t", OString()).
274 replaceAll(" ", OString());
275 if (( !bReadOver
) && ( sTestToken
.indexOf("#ifndef__RSC_PARSER") == 0 ))
276 bReadOver
= sal_True
;
277 else if (( bReadOver
) && ( sTestToken
.indexOf("#endif") == 0 ))
278 bReadOver
= sal_False
;
280 if ((( nToken
< FILTER_LEVEL
) || ( bReadOver
)) &&
281 (!(( bNextMustBeDefineEOL
) && ( sOrig
== "\n" )))) {
282 // this tokens are not mandatory for parsing, so ignore them ...
284 WriteToMerged( sOrig
, false ); // ... or write them directly to dest.
288 ResData
*pResData
= NULL
;
290 // res. exists at cur. level
291 pResData
= ( (nLevel
-1) < aResStack
.size() ) ? aResStack
[ nLevel
-1 ] : NULL
;
293 else if (( nToken
!= RESOURCE
) &&
294 ( nToken
!= RESOURCEEXPR
) &&
295 ( nToken
!= SMALRESOURCE
) &&
296 ( nToken
!= LEVELUP
) &&
297 ( nToken
!= NORMDEFINE
) &&
298 ( nToken
!= RSCDEFINE
) &&
299 ( nToken
!= CONDITION
) &&
300 ( nToken
!= PRAGMA
))
302 // no res. exists at cur. level so return
304 WriteToMerged( sOrig
, false );
307 // #define NO_LOCALIZE_EXPORT
310 WriteToMerged( sOrig
, false );
317 if (( nToken
!= EMPTYLINE
) && ( nToken
!= LEVELDOWN
) && ( nToken
!= LEVELUP
)) {
318 // cur. res. defined in macro
319 if ( bNextMustBeDefineEOL
) {
320 if ( nToken
!= RSCDEFINELEND
) {
321 // end of macro found, so destroy res.
323 Execute( LEVELDOWN
, "" );
324 bNextMustBeDefineEOL
= sal_False
;
327 // next line also in macro definition
328 bNextMustBeDefineEOL
= sal_False
;
330 WriteToMerged( sOrig
, false );
337 sal_Bool bExecuteDown
= sal_False
;
338 if ( nToken
!= LEVELDOWN
) {
339 sal_uInt16 nOpen
= 0;
340 sal_uInt16 nClose
= 0;
341 sal_Bool bReadOver1
= sal_False
;
343 for ( i
= 0; i
< sToken
.getLength(); i
++ ) {
344 if ( sToken
[i
] == '"' )
345 bReadOver1
= !bReadOver1
;
346 if ( !bReadOver1
&& ( sToken
[i
] == '{' ))
350 bReadOver1
= sal_False
;
351 for ( i
= 0; i
< sToken
.getLength(); i
++ ) {
352 if ( sToken
[i
] == '"' )
353 bReadOver1
= !bReadOver1
;
354 if ( !bReadOver1
&& ( sToken
[i
] == '}' ))
358 if ( nOpen
< nClose
)
359 bExecuteDown
= sal_True
;
364 sToken
= sToken
.replace('\r', ' ').replace('\t', ' ');
367 sToken
= sToken
.replaceFirst(" ", " ", &n
);
372 if( sToken
.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("#define NO_LOCALIZE_EXPORT")) ){
377 WriteToMerged( sOrig
, false );
383 bDefine
= sal_True
; // res. defined in macro
387 bDontWriteOutput
= sal_False
;
388 if ( nToken
!= RSCDEFINE
)
389 bNextMustBeDefineEOL
= sal_False
;
390 // this is the beginning of a new res.
393 aResStack
[ nLevel
- 2 ]->bChild
= sal_True
;
396 // create new instance for this res. and fill mandatory fields
398 pResData
= new ResData( FullId() , sFilename
);
399 aResStack
.push_back( pResData
);
400 sToken
= sToken
.replaceAll("\n", OString()).
401 replaceAll("\r", OString()).
402 replaceAll("{", OString()).replace('\t', ' ');
403 sToken
= sToken
.trim();
404 OString sTLower
= sToken
.getToken(0, ' ').toAsciiLowerCase();
405 pResData
->sResTyp
= sTLower
;
406 OString
sId( sToken
.copy( pResData
->sResTyp
.getLength() + 1 ));
408 if ( sId
.indexOf( '#' ) != -1 )
410 // between ResTyp, Id and paranthes is a precomp. condition
413 sId
= sId
.getToken(0, '#', n
);
414 sCondition
+= sId
.getToken(0, '#', n
);
416 sId
= sId
.getToken(0, '/');
418 sId
= sId
.replaceAll("\t", OString());
419 pResData
->SetId( sId
, ID_LEVEL_IDENTIFIER
);
420 if (!sCondition
.isEmpty())
422 Execute( CONDITION
, ""); // execute the precomp. condition
427 bDontWriteOutput
= sal_False
;
428 // this is the beginning of a new res.
429 bNextMustBeDefineEOL
= sal_False
;
432 aResStack
[ nLevel
- 2 ]->bChild
= sal_True
;
435 // create new instance for this res. and fill mandatory fields
437 pResData
= new ResData( FullId() , sFilename
);
438 aResStack
.push_back( pResData
);
439 sToken
= sToken
.replaceAll("\n", OString()).
440 replaceAll("\r", OString()).
441 replaceAll("{", OString()).
442 replaceAll("\t", OString()).
443 replaceAll(" ", OString()).
444 replaceAll("\\", OString()).toAsciiLowerCase();
445 pResData
->sResTyp
= sToken
;
455 bDontWriteOutput
= sal_False
;
458 sLowerTyp
= "unknown";
461 aResStack
[ nLevel
- 2 ]->bChild
= sal_True
;
464 ResData
*pNewData
= new ResData( FullId() , sFilename
);
465 pNewData
->sResTyp
= sLowerTyp
;
466 aResStack
.push_back( pNewData
);
472 bDontWriteOutput
= sal_False
;
474 if ( bDefine
&& (nLevel
== 1 )) {
476 bNextMustBeDefineEOL
= sal_False
;
478 WriteData( pResData
);
479 ResStack::iterator it
= aResStack
.begin();
480 ::std::advance( it
, nLevel
-1 );
482 aResStack
.erase( it
);
488 bNextMustBeDefineEOL
= sal_True
;
499 bDontWriteOutput
= sal_False
;
500 // interpret different types of assignement
502 OString sKey
= sToken
.getToken(0, '=', n
).
503 replaceAll(" ", OString()).
504 replaceAll("\t", OString());
505 OString sValue
= sToken
.getToken(0, '=', n
);
506 CleanValue( sValue
);
507 sKey
= sKey
.toAsciiUpperCase();
508 if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("IDENTIFIER")))
511 sValue
.replaceAll("\t", OString()).
512 replaceAll(" ", OString()));
513 pResData
->SetId(sId
, ID_LEVEL_IDENTIFIER
);
515 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("HELPID")))
517 pResData
->sHelpId
= sValue
;
519 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("STRINGLIST")))
521 pResData
->bList
= sal_True
;
523 m_sListLang
= SOURCE_LANGUAGE
;
527 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("FILTERLIST")))
529 pResData
->bList
= sal_True
;
531 m_sListLang
= SOURCE_LANGUAGE
;
535 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("UIENTRIES")))
537 pResData
->bList
= sal_True
;
538 nList
= LIST_UIENTRIES
;
539 m_sListLang
= SOURCE_LANGUAGE
;
543 if (sToken
.indexOf( '{' ) != -1
544 && (lcl_countOccurrences(sToken
, '{')
545 > lcl_countOccurrences(sToken
, '}')))
547 Parse( LEVELUP
, "" );
554 bDontWriteOutput
= sal_False
;
556 sToken
.replaceAll(" ", OString()).toAsciiLowerCase());
557 sal_Int32 nPos
= sTmpToken
.indexOf("[en-us]=");
560 sTmpToken
.copy(0 , nPos
).replaceAll(" ", OString()).
561 replaceAll("\t", OString()));
562 OString sValue
= sToken
.getToken(1, '=');
563 CleanValue( sValue
);
564 sKey
= sKey
.toAsciiUpperCase();
565 if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("STRINGLIST")))
567 pResData
->bList
= sal_True
;
569 m_sListLang
= SOURCE_LANGUAGE
;
573 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("FILTERLIST")))
575 pResData
->bList
= sal_True
;
577 m_sListLang
= SOURCE_LANGUAGE
;
581 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("PAIREDLIST")))
583 pResData
->bList
= sal_True
;
585 m_sListLang
= SOURCE_LANGUAGE
;
589 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("ITEMLIST")))
591 pResData
->bList
= sal_True
;
593 m_sListLang
= SOURCE_LANGUAGE
;
597 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("UIENTRIES")))
599 pResData
->bList
= sal_True
;
600 nList
= LIST_UIENTRIES
;
601 m_sListLang
= SOURCE_LANGUAGE
;
611 // this is an entry for a String- or FilterList
615 OString
sEntry(sToken
.getToken(1, '"', n
));
616 if ( lcl_countOccurrences(sToken
, '"') > 2 )
618 if ( sEntry
== "\\\"" )
620 InsertListEntry( sEntry
, sOrig
);
626 bDontWriteOutput
= sal_False
;
629 CutComment( sToken
);
631 // this is a text line!!!
632 OString
t(sToken
.getToken(0, '='));
634 t
.getToken(0, '[').replaceAll(" ", OString()).
635 replaceAll("\t", OString()));
636 OString
sText( GetText( sToken
, nToken
));
638 if ( sToken
.getToken(0, '=').indexOf('[') != -1 )
640 sLang
= sToken
.getToken(0, '=').getToken(1, '[').
644 OString sLangIndex
= sLang
;
645 OString sOrigKey
= sKey
;
646 if ( !sText
.isEmpty() && !sLang
.isEmpty() )
648 sKey
= sKey
.toAsciiUpperCase();
649 if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("TEXT")) ||
650 sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("MESSAGE")) ||
651 sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("CUSTOMUNITTEXT")) ||
652 sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("SLOTNAME")) ||
653 sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("UINAME")))
656 if ( sLangIndex
.equalsIgnoreAsciiCase("en-US") )
657 pResData
->SetId( sText
, ID_LEVEL_TEXT
);
659 pResData
->bText
= sal_True
;
660 pResData
->sTextTyp
= sOrigKey
;
663 if (!pResData
->sText
[ sLangIndex
].isEmpty())
665 OStringBuffer
sError(RTL_CONSTASCII_STRINGPARAM("Language "));
666 sError
.append(sLangIndex
);
667 sError
.append(RTL_CONSTASCII_STRINGPARAM("defined twice"));
668 yyerror(sError
.getStr());
670 pResData
->sText
[ sLangIndex
] = sText
;
673 else if ( sKey
== "HELPTEXT" ) {
675 pResData
->bHelpText
= sal_True
;
678 if (!pResData
->sHelpText
[ sLangIndex
].isEmpty())
680 OStringBuffer
sError(RTL_CONSTASCII_STRINGPARAM("Language "));
681 sError
.append(sLangIndex
);
682 sError
.append(" defined twice");
683 YYWarning(sError
.getStr());
685 pResData
->sHelpText
[ sLangIndex
] = sText
;
688 else if ( sKey
== "QUICKHELPTEXT" ) {
690 pResData
->bQuickHelpText
= sal_True
;
693 if (!pResData
->sQuickHelpText
[ sLangIndex
].isEmpty())
695 OStringBuffer
sError(RTL_CONSTASCII_STRINGPARAM("Language "));
696 sError
.append(sLangIndex
);
697 sError
.append(RTL_CONSTASCII_STRINGPARAM(" defined twice"));
698 YYWarning(sError
.getStr());
700 pResData
->sQuickHelpText
[ sLangIndex
] = sText
;
703 else if ( sKey
== "TITLE" ) {
705 pResData
->bTitle
= sal_True
;
708 if ( !pResData
->sTitle
[ sLangIndex
].isEmpty())
710 OStringBuffer
sError(RTL_CONSTASCII_STRINGPARAM("Language "));
711 sError
.append(sLangIndex
);
712 sError
.append(RTL_CONSTASCII_STRINGPARAM(" defined twice"));
713 YYWarning(sError
.getStr());
715 pResData
->sTitle
[ sLangIndex
] = sText
;
718 else if ( sKey
== "ACCESSPATH" ) {
719 pResData
->SetId( sText
, ID_LEVEL_ACCESSPATH
);
721 else if ( sKey
== "FIELDNAME" ) {
722 pResData
->SetId( sText
, ID_LEVEL_FIELDNAME
);
728 bDontWriteOutput
= sal_True
;
733 bDontWriteOutput
= sal_False
;
737 bDontWriteOutput
= sal_False
;
740 bDontWriteOutput
= sal_False
;
742 WriteData( pResData
, sal_True
);
747 bDontWriteOutput
= sal_False
;
749 bNextMustBeDefineEOL
= sal_False
;
752 Parse( LEVELDOWN
, "" );
757 bDontWriteOutput
= sal_False
;
758 fprintf(stderr
, "ERROR: archaic PRAGMA %s\n", sToken
.getStr());
763 bDontWriteOutput
= sal_True
;
766 if ( bWriteToMerged
) {
767 // the current token must be written to dest. without merging
769 if( bDefine
&& sOrig
.getLength() > 2 ){
770 for( sal_uInt16 n
= 0 ; n
< sOrig
.getLength() ; n
++ ){
771 if( sOrig
[n
] == '\n' && sOrig
[n
-1] != '\\'){
772 sOrig
= sOrig
.replaceAt(n
++, 0, "\\");
776 WriteToMerged( sOrig
, false);
779 if ( bExecuteDown
) {
780 Parse( LEVELDOWN
, "" );
786 void Export::CutComment( OString
&rText
)
788 if (rText
.indexOf("//") != -1) {
789 OString
sWork(rText
.replaceAll("\\\"", "XX"));
791 for (sal_Int32 i
= 0; i
< sWork
.getLength() - 1; ++i
) {
792 if (sWork
[i
] == '"') {
794 } else if (sWork
[i
] == '/' && !bInner
&& sWork
[i
+ 1] == '/' ) {
795 rText
= rText
.copy(0, i
);
802 sal_Bool
Export::WriteData( ResData
*pResData
, sal_Bool bCreateNew
)
805 MergeRest( pResData
);
809 // mandatory to export: en-US
811 if (( !pResData
->sText
[ SOURCE_LANGUAGE
].isEmpty())
813 ( !pResData
->sHelpText
[ SOURCE_LANGUAGE
].isEmpty())
815 ( !pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
].isEmpty())
817 ( !pResData
->sTitle
[ SOURCE_LANGUAGE
].isEmpty()))
820 OString sGID
= pResData
->sGId
;
823 sGID
= pResData
->sId
;
825 sLID
= pResData
->sId
;
832 sXText
= pResData
->sText
[ SOURCE_LANGUAGE
];
833 if (!pResData
->sText
[ X_COMMENT
].isEmpty())
834 sXHText
= pResData
->sText
[ X_COMMENT
];
836 sXHText
= pResData
->sHelpText
[ SOURCE_LANGUAGE
];
837 sXQHText
= pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
];
838 sXTitle
= pResData
->sTitle
[ SOURCE_LANGUAGE
];
840 if( !sXText
.isEmpty() )
842 ConvertExportContent(sXText
);
843 ConvertExportContent(sXHText
);
844 common::writePoEntry(
845 "Transex3", *aOutput
.mPo
, global::inputPathname
,
846 pResData
->sResTyp
, sGID
, sLID
, sXHText
, sXText
);
848 if( !sXQHText
.isEmpty() )
850 ConvertExportContent(sXQHText
);
851 common::writePoEntry(
852 "Transex3", *aOutput
.mPo
, global::inputPathname
, pResData
->sResTyp
,
853 sGID
, sLID
, OString(), sXQHText
, PoEntry::TQUICKHELPTEXT
);
855 if( !sXTitle
.isEmpty() )
857 ConvertExportContent(sXTitle
);
858 common::writePoEntry(
859 "Transex3", *aOutput
.mPo
, global::inputPathname
, pResData
->sResTyp
,
860 sGID
, sLID
, OString(), sXTitle
, PoEntry::TTITLE
);
864 pResData
->sText
[ SOURCE_LANGUAGE
] = "";
865 pResData
->sHelpText
[ SOURCE_LANGUAGE
] = "";
866 pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
]= "";
867 pResData
->sTitle
[ SOURCE_LANGUAGE
] = "";
870 if ( pResData
->pStringList
) {
871 OString
sList( "stringlist" );
872 WriteExportList( pResData
, pResData
->pStringList
, sList
, bCreateNew
);
874 pResData
->pStringList
= 0;
876 if ( pResData
->pFilterList
) {
877 OString
sList( "filterlist" );
878 WriteExportList( pResData
, pResData
->pFilterList
, sList
, bCreateNew
);
880 pResData
->pFilterList
= 0;
882 if ( pResData
->pItemList
) {
883 OString
sList( "itemlist" );
884 WriteExportList( pResData
, pResData
->pItemList
, sList
, bCreateNew
);
886 pResData
->pItemList
= 0;
888 if ( pResData
->pPairedList
) {
889 OString
sList( "pairedlist" );
890 WriteExportList( pResData
, pResData
->pPairedList
, sList
, bCreateNew
);
892 pResData
->pPairedList
= 0;
894 if ( pResData
->pUIEntries
) {
895 OString
sList( "uientries" );
896 WriteExportList( pResData
, pResData
->pUIEntries
, sList
, bCreateNew
);
898 pResData
->pUIEntries
= 0;
903 OString
Export::GetPairedListID(const OString
& rText
)
905 // < "STRING" ; IDENTIFIER ; > ;
906 return rText
.getToken(1, ';').toAsciiUpperCase().replace('\t', ' ').trim();
909 OString
Export::GetPairedListString(const OString
& rText
)
911 // < "STRING" ; IDENTIFIER ; > ;
912 OString
sString(rText
.getToken(0, ';').replace('\t', ' '));
913 sString
= sString
.trim();
914 OString
s1(sString
.copy(sString
.indexOf('"') + 1));
915 sString
= s1
.copy(0, s1
.lastIndexOf('"'));
916 return sString
.trim();
919 OString
Export::StripList(const OString
& rText
)
921 OString s1
= rText
.copy( rText
.indexOf('\"') + 1);
922 return s1
.copy( 0 , s1
.lastIndexOf('\"'));
925 sal_Bool
Export::WriteExportList(ResData
*pResData
, ExportList
*pExportList
,
926 const OString
&rTyp
, sal_Bool bCreateNew
)
928 OString
sGID(pResData
->sGId
);
930 sGID
= pResData
->sId
;
933 sGID
+= pResData
->sId
;
934 while (sGID
.getLength() != 0 && sGID
[sGID
.getLength() - 1] == '.') {
935 sGID
= sGID
.copy(0, sGID
.getLength() - 1);
939 for ( size_t i
= 0; pExportList
!= NULL
&& i
< pExportList
->size(); i
++ )
941 ExportListEntry
*pEntry
= (*pExportList
)[ i
];
944 OString
sText((*pEntry
)[ SOURCE_LANGUAGE
] );
946 // Strip PairList Line String
947 if (rTyp
.equalsIgnoreAsciiCase("pairedlist"))
949 sLID
= GetPairedListID( sText
);
950 sText
= GetPairedListString( sText
);
954 sLID
= OString::valueOf(static_cast<sal_Int64
>(i
+ 1));
955 sText
= StripList( sText
);
956 if( sText
== "\\\"" )
959 ConvertExportContent(sText
);
960 common::writePoEntry(
961 "Transex3", *aOutput
.mPo
, global::inputPathname
,
962 rTyp
, sGID
, sLID
, OString(), sText
);
973 OString
Export::FullId()
978 sFull
.append(aResStack
[ 0 ]->sId
);
979 for ( size_t i
= 1; i
< nLevel
- 1; ++i
)
981 OString sToAdd
= aResStack
[ i
]->sId
;
982 if (!sToAdd
.isEmpty())
983 sFull
.append('.').append(sToAdd
);
986 if (sFull
.getLength() > 255)
988 OString
sError(RTL_CONSTASCII_STRINGPARAM("GroupId > 255 chars"));
989 printf("GroupID = %s\n", sFull
.getStr());
990 yyerror(sError
.getStr());
993 return sFull
.makeStringAndClear();
996 void Export::InsertListEntry(const OString
&rText
, const OString
&rLine
)
998 ResData
*pResData
= ( nLevel
-1 < aResStack
.size() ) ? aResStack
[ nLevel
-1 ] : NULL
;
1000 ExportList
*pList
= NULL
;
1001 if ( nList
== LIST_STRING
) {
1002 pList
= pResData
->pStringList
;
1004 pResData
->pStringList
= new ExportList();
1005 pList
= pResData
->pStringList
;
1009 else if ( nList
== LIST_FILTER
) {
1010 pList
= pResData
->pFilterList
;
1012 pResData
->pFilterList
= new ExportList();
1013 pList
= pResData
->pFilterList
;
1017 else if ( nList
== LIST_ITEM
) {
1018 pList
= pResData
->pItemList
;
1020 pResData
->pItemList
= new ExportList();
1021 pList
= pResData
->pItemList
;
1025 else if ( nList
== LIST_PAIRED
) {
1026 pList
= pResData
->pPairedList
;
1028 pResData
->pPairedList
= new ExportList();
1029 pList
= pResData
->pPairedList
;
1033 else if ( nList
== LIST_UIENTRIES
) {
1034 pList
= pResData
->pUIEntries
;
1036 pResData
->pUIEntries
= new ExportList();
1037 pList
= pResData
->pUIEntries
;
1044 if ( nListIndex
+ 1 > pList
->size())
1046 ExportListEntry
*pNew
= new ExportListEntry();
1047 (*pNew
)[LIST_REFID
] = OString::number(REFID_NONE
);
1048 pList
->push_back(pNew
);
1050 ExportListEntry
*pCurEntry
= (*pList
)[ nListIndex
];
1052 // For paired list use the line to set proper lid
1053 if( nList
== LIST_PAIRED
){
1054 (*pCurEntry
)[ m_sListLang
] = rLine
;
1056 (*pCurEntry
)[ m_sListLang
] = rText
;
1058 if ( m_sListLang
.equalsIgnoreAsciiCase("en-US") ) {
1059 (*pCurEntry
)[ SOURCE_LANGUAGE
] = rLine
;
1061 pList
->NewSourceLanguageListEntry();
1067 void Export::CleanValue( OString
&rValue
)
1069 while ( !rValue
.isEmpty()) {
1070 if (( rValue
[0] == ' ' ) || ( rValue
[0] == '\t' ))
1071 rValue
= rValue
.copy( 1 );
1076 if ( !rValue
.isEmpty()) {
1077 for ( sal_Int32 i
= rValue
.getLength() - 1; i
> 0; i
-- ) {
1078 if (( rValue
[i
] == ' ' ) || ( rValue
[i
] == '\t' ) ||
1079 ( rValue
[i
] == '\n' ) || ( rValue
[i
] == ';' ) ||
1080 ( rValue
[i
] == '{' ) || ( rValue
[i
] == '\\' ) ||
1081 ( rValue
[i
] == '\r' ))
1082 rValue
= rValue
.copy(0, i
);
1089 #define TXT_STATE_TEXT 0x001
1090 #define TXT_STATE_MACRO 0x002
1092 OString
Export::GetText(const OString
&rSource
, int nToken
)
1100 OString
sTmp(rSource
.copy(rSource
.indexOf('=')));
1102 sTmp
= sTmp
.replaceAll("\n", OString()).
1103 replaceAll("\r", OString()).
1104 replaceAll("\\\\\"", "-=<[BSlashBSlashHKom]>=-\"").
1105 replaceAll("\\\"", "-=<[Hochkomma]>=-").
1106 replaceAll("\\\x7f", "-=<[0x7F]>=-").
1107 replaceAll("\\0x7F", "-=<[0x7F]>=-");
1109 sal_uInt16 nState
= TXT_STATE_TEXT
;
1110 for (sal_Int32 i
= 1; i
<= lcl_countOccurrences(sTmp
, '"'); ++i
)
1112 OString
sToken(sTmp
.getToken(i
, '"'));
1113 if (!sToken
.isEmpty()) {
1114 if ( nState
== TXT_STATE_TEXT
) {
1116 nState
= TXT_STATE_MACRO
;
1119 sToken
= sToken
.replace('\t', ' ');
1122 sToken
= sToken
.replaceFirst(" ", " ", &n
);
1127 sToken
= sToken
.trim();
1128 if (!sToken
.isEmpty()) {
1133 nState
= TXT_STATE_TEXT
;
1138 sReturn
= sReturn
.replaceAll("-=<[0x7F]>=-", "\x7f").
1139 replaceAll("-=<[Hochkomma]>=-", "\"").
1140 replaceAll("-=<[BSlashBSlashHKom]>=-", "\\\\").
1141 replaceAll("\\\\", "-=<[BSlashBSlash]>=-").
1142 replaceAll("-=<[BSlashBSlash]>=-", "\\");
1149 void Export::WriteToMerged(const OString
&rText
, bool bSDFContent
)
1151 OString
sText(rText
);
1154 sText
= sText
.replaceFirst(" \n", "\n", &n
);
1159 if (pParseQueue
->bNextIsM
&& bSDFContent
&& sText
.getLength() > 2) {
1160 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
1161 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
1162 sText
= sText
.replaceAt(n
++, 0, "\\");
1165 } else if (pParseQueue
->bLastWasM
&& sText
.getLength() > 2) {
1166 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
1167 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
1168 sText
= sText
.replaceAt(n
++, 0, "\\");
1170 if (sText
[n
] == '\n') {
1171 pParseQueue
->bMflag
= true;
1174 } else if (pParseQueue
->bCurrentIsM
&& bSDFContent
&& sText
.getLength() > 2)
1176 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
1177 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
1178 sText
= sText
.replaceAt(n
++, 0, "\\");
1179 pParseQueue
->bMflag
= true;
1182 } else if (pParseQueue
->bMflag
) {
1183 for (sal_Int32 n
= 1; n
< sText
.getLength(); ++n
) {
1184 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
1185 sText
= sText
.replaceAt(n
++, 0, "\\");
1188 } for (sal_Int32 i
= 0; i
< sText
.getLength(); ++i
) {
1189 if (sText
[i
] == '\n') {
1190 *aOutput
.mSimple
<< '\n';
1192 char cChar
= sText
[i
];
1193 *aOutput
.mSimple
<< cChar
;
1198 void Export::ConvertMergeContent( OString
&rText
)
1200 rText
= rText
.replaceAll("\\\'","\'"); // Temporary: until PO files contain escaped single quotes
1201 // (Maybe next PO update solve this)
1204 rText
.replaceAll("\x7f","\\0x7F"),
1205 "\n""\t""\\""\"","\\n""\\t""\\\\""\\\"");
1207 rText
= "\"" + rText
+ "\"";
1210 void Export::ConvertExportContent( OString
& rText
)
1212 rText
= helper::unEscapeAll(rText
,"\\n""\\t""\\\\""\\\"","\n""\t""\\""\"");
1215 bool Export::GetAllMergeEntrysOfList(ResData
*pResData
, std::vector
<MergeEntrys
*>& o_vMergeEntrys
, ExportList
*& o_pList
)
1217 o_vMergeEntrys
.clear();
1220 if (!pResData
->sGId
.isEmpty())
1221 pResData
->sGId
= pResData
->sGId
+ OString('.');
1222 pResData
->sGId
= pResData
->sGId
+ pResData
->sId
;
1224 // Find out the type of List
1225 MergeEntrys
* pEntrysOfFirstItem
= 0;
1226 sal_uInt16 nType
= LIST_STRING
;
1227 bool bPairedList
= false;
1228 while( !pEntrysOfFirstItem
&& nType
<= LIST_UIENTRIES
)
1232 case LIST_STRING
: pResData
->sResTyp
= "stringlist"; o_pList
= pResData
->pStringList
; bPairedList
= false; break;
1233 case LIST_FILTER
: pResData
->sResTyp
= "filterlist"; o_pList
= pResData
->pFilterList
; bPairedList
= false; break;
1234 case LIST_UIENTRIES
: pResData
->sResTyp
= "uientries"; o_pList
= pResData
->pUIEntries
;bPairedList
= false; break;
1235 case LIST_ITEM
: pResData
->sResTyp
= "itemlist"; o_pList
= pResData
->pItemList
; bPairedList
= false; break;
1236 case LIST_PAIRED
: pResData
->sResTyp
= "pairedlist"; o_pList
= pResData
->pPairedList
; bPairedList
= true; break;
1239 // Set matching pairedlist identifier
1240 if( bPairedList
&& pResData
->pPairedList
)
1242 ExportListEntry
* pListE
= ( ExportListEntry
* ) (*pResData
->pPairedList
)[ 0 ];
1243 pResData
->sId
= GetPairedListID ( (*pListE
)[ SOURCE_LANGUAGE
] );
1246 pResData
->sId
= "1";
1248 pEntrysOfFirstItem
= pMergeDataFile
->GetMergeEntrys( pResData
);
1252 if( !pEntrysOfFirstItem
)
1260 sal_uInt16 nMaxIndex
= 0;
1263 nMaxIndex
= o_pList
->GetSourceLanguageListEntryCount();
1266 * Check whether count of listentries match with count
1267 * of translated items. If not than write origin items
1268 * to the list to avoid mixed translations
1269 * (exclude pairedlist)
1273 MergeEntrys
* pEntrys
;
1274 // MergeData contains longer list
1275 pResData
->sId
= OString::number(nMaxIndex
+1);
1276 pEntrys
= pMergeDataFile
->GetMergeEntrys( pResData
);
1279 // MergeData contains shorter list
1280 pResData
->sId
= OString::number(nMaxIndex
);
1281 pEntrys
= pMergeDataFile
->GetMergeEntrys( pResData
);
1284 pResData
->sId
= "1";
1287 o_vMergeEntrys
.push_back(pEntrysOfFirstItem
);
1289 for( sal_uInt16 nLIndex
= 2; nLIndex
<= nMaxIndex
; ++nLIndex
)
1291 // Set matching pairedlist identifier
1294 ExportListEntry
* pListE
= ( ExportListEntry
* )(*pResData
->pPairedList
)[ ( nLIndex
) -1 ];
1297 pResData
->sId
= GetPairedListID ( (*pListE
)[ SOURCE_LANGUAGE
] );
1301 pResData
->sId
= OString::number(nLIndex
);
1303 MergeEntrys
* pEntrys
= pMergeDataFile
->GetMergeEntrys( pResData
);
1306 o_vMergeEntrys
.push_back(pEntrys
);
1312 void Export::ResData2Output( MergeEntrys
*pEntry
, sal_uInt16 nType
, const OString
& rTextType
)
1314 sal_Bool bAddSemicolon
= sal_False
;
1315 sal_Bool bFirst
= sal_True
;
1318 for( unsigned int n
= 0; n
< aLanguages
.size(); n
++ ){
1319 sCur
= aLanguages
[ n
];
1322 sal_Bool bText
= pEntry
->GetText( sText
, nType
, sCur
, sal_True
);
1323 if ( bText
&& !sText
.isEmpty() ) {
1325 if ( bNextMustBeDefineEOL
) {
1327 sOutput
+= "\t\\\n";
1329 sOutput
+= ";\t\\\n";
1334 sOutput
+= rTextType
;
1336 if ( !sCur
.equalsIgnoreAsciiCase("en-US") ) {
1342 ConvertMergeContent( sText
);
1347 else if ( !bNextMustBeDefineEOL
)
1350 bAddSemicolon
= sal_True
;
1351 for ( sal_uInt16 j
= 1; j
< nLevel
; j
++ )
1353 WriteToMerged( sOutput
, true );
1358 if ( bAddSemicolon
) {
1359 OString
sOutput( ";" );
1360 WriteToMerged( sOutput
, false );
1364 void Export::MergeRest( ResData
*pResData
, sal_uInt16 nMode
)
1366 if ( !pMergeDataFile
){
1367 pMergeDataFile
= new MergeDataFile( sMergeSrc
, global::inputPathname
, false );
1368 aLanguages
= pMergeDataFile
->GetLanguages();
1372 case MERGE_MODE_NORMAL
: {
1373 MergeEntrys
*pEntry
= 0;
1374 if( pResData
->bText
|| pResData
->bQuickHelpText
|| pResData
->bTitle
)
1375 pEntry
= pMergeDataFile
->GetMergeEntrys( pResData
);
1378 if ( pResData
->bText
)
1379 ResData2Output( pEntry
, STRING_TYP_TEXT
, pResData
->sTextTyp
);
1381 if ( pResData
->bQuickHelpText
)
1382 ResData2Output( pEntry
, STRING_TYP_QUICKHELPTEXT
, OString("QuickHelpText") );
1384 if ( pResData
->bTitle
)
1385 ResData2Output( pEntry
, STRING_TYP_TITLE
, OString("Title") );
1390 if ( pResData
->bList
) {
1391 OString sOldId
= pResData
->sId
;
1392 OString sOldGId
= pResData
->sGId
;
1393 OString sOldTyp
= pResData
->sResTyp
;
1394 sal_uInt16 nOldListTyp
= nList
;
1397 for ( sal_uInt16 i
= 1; i
< nLevel
-1; i
++ )
1400 std::vector
<MergeEntrys
*> vMergeEntryVector
;
1401 ExportList
* pList
= 0;
1402 bool bTranslateList
= GetAllMergeEntrysOfList(pResData
, vMergeEntryVector
, pList
);
1407 for( unsigned int n
= 0; n
< aLanguages
.size(); n
++ )
1409 sCur
= aLanguages
[ n
];
1411 sal_uInt16 nLIndex
= 0;
1412 sal_uInt16 nMaxIndex
= pList
->GetSourceLanguageListEntryCount();
1413 while( nLIndex
< nMaxIndex
)
1417 OStringBuffer sHead
;
1418 if ( bNextMustBeDefineEOL
)
1419 sHead
.append("\\\n\t");
1420 sHead
.append(sSpace
);
1424 sHead
.append("StringList ");
1427 sHead
.append("FilterList ");
1430 sHead
.append("ItemList ");
1433 sHead
.append("PairedList ");
1435 case LIST_UIENTRIES
:
1436 sHead
.append("UIEntries ");
1441 sHead
.append(" ] ");
1442 if ( bDefine
|| bNextMustBeDefineEOL
)
1444 sHead
.append("= \\\n");
1445 sHead
.append(sSpace
);
1446 sHead
.append("\t{\\\n\t");
1450 sHead
.append("= \n");
1451 sHead
.append(sSpace
);
1452 sHead
.append("\t{\n\t");
1454 WriteToMerged(sHead
.makeStringAndClear() , true);
1457 if ( pList
&& (*pList
)[ nLIndex
] )
1458 sLine
= ( *(*pList
)[ nLIndex
])[ SOURCE_LANGUAGE
];
1460 if ( sLine
.indexOf( '>' ) != -1 ) {
1461 if (( nList
!= LIST_UIENTRIES
) &&
1462 (( sLine
.indexOf( '{' ) == -1 ) ||
1463 ( sLine
.indexOf( '{' ) >= sLine
.indexOf( '"' ))) &&
1464 (( sLine
.indexOf( '<' ) == -1 ) ||
1465 ( sLine
.indexOf( '<' ) >= sLine
.indexOf( '"' ))))
1467 sLine
= sLine
.replaceFirst("\"", "< \"" );
1471 if( bTranslateList
&& nLIndex
< vMergeEntryVector
.size() )
1475 bText
= vMergeEntryVector
[nLIndex
]->GetText( sText
, STRING_TYP_TEXT
, sCur
, sal_True
);
1476 if ( bText
&& !sText
.isEmpty() )
1478 ConvertMergeContent( sText
);
1479 OString sPre
= sLine
.copy( 0 , sLine
.indexOf('"') );
1480 OString sPost
= sLine
.copy( sLine
.lastIndexOf('"') + 1 );
1481 sLine
= sPre
+ sText
+ sPost
;
1485 OString
sText1( "\t" );
1487 if ( bDefine
|| bNextMustBeDefineEOL
)
1493 WriteToMerged( sText1
,true );
1496 if ( nLIndex
> 0 ) {
1498 if (!sSpace
.isEmpty()) {
1499 sFooter
= sSpace
.copy(1);
1501 if ( bNextMustBeDefineEOL
)
1503 else if ( !bDefine
)
1504 sFooter
+= "};\n\t";
1507 WriteToMerged( sFooter
,true );
1512 pResData
->sId
= sOldId
;
1513 pResData
->sGId
= sOldGId
;
1514 pResData
->sResTyp
= sOldTyp
;
1515 nList
= nOldListTyp
;
1519 case MERGE_MODE_LIST
: {
1523 pParseQueue
->bMflag
= false;
1526 void Export::SetChildWithText()
1528 if ( aResStack
.size() > 1 ) {
1529 for ( size_t i
= 0; i
< aResStack
.size() - 1; i
++ ) {
1530 aResStack
[ i
]->bChildWithText
= sal_True
;
1535 void ParserQueue::Push( const QueueEntry
& aEntry
)
1537 sal_Int32 nLen
= aEntry
.sLine
.getLength();
1540 aQueueCur
->push( aEntry
);
1541 if( nLen
> 1 && aEntry
.sLine
[nLen
-1] == '\n' )
1543 else if ( aEntry
.nTyp
!= IGNOREDTOKENS
){
1544 if( nLen
> 1 && ( aEntry
.sLine
[nLen
-1] == '\\') ){
1549 bCurrentIsM
= false;
1554 aQueueNext
->push( aEntry
);
1555 if( nLen
> 1 && aEntry
.sLine
[nLen
-1] != '\n' ){
1556 if( nLen
> 1 && ( aEntry
.sLine
[nLen
-1] == '\\') ){
1564 }else if( nLen
> 2 && aEntry
.sLine
[nLen
-1] == '\n' ){
1565 if( aEntry
.nTyp
!= IGNOREDTOKENS
){
1566 if( nLen
> 2 && ( aEntry
.sLine
[nLen
-2] == '\\') ){
1577 bLastWasM
= bCurrentIsM
;
1579 bCurrentIsM
= bNextIsM
;
1581 aQueueCur
= aQueueNext
;
1589 bLastWasM
= bCurrentIsM
;
1591 bCurrentIsM
= bNextIsM
;
1593 aQueueCur
= aQueueNext
;
1599 void ParserQueue::Close(){
1603 bLastWasM
= bCurrentIsM
;
1604 bCurrentIsM
= bNextIsM
;
1606 aQueueCur
= aQueueNext
;
1612 void ParserQueue::Pop( std::queue
<QueueEntry
>& aQueue
)
1614 while (!aQueue
.empty())
1616 QueueEntry aEntry
= aQueue
.front();
1618 aExport
.Execute(aEntry
.nTyp
, aEntry
.sLine
.getStr());
1622 ParserQueue::ParserQueue( Export
& aExportObj
)
1624 bCurrentIsM( false ),
1628 aExport( aExportObj
) ,
1631 aQueueNext
= new std::queue
<QueueEntry
>;
1632 aQueueCur
= new std::queue
<QueueEntry
>;
1636 ParserQueue::~ParserQueue(){
1637 if( aQueueNext
) delete aQueueNext
;
1638 if( aQueueCur
) delete aQueueCur
;
1641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */