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"
28 #include "boost/scoped_ptr.hpp"
35 #include <rtl/strbuf.hxx>
37 void yyerror( const char * );
38 void YYWarning( const char * );
42 MergeDataFile
* pMergeDataFile
= 0; //TODO
46 OString inputPathname
;
47 boost::scoped_ptr
< Export
> exporter
;
51 static OString
lcl_GetListTyp( const sal_uInt16 nTyp
, const bool bUpperCamelCase
)
57 sType
= bUpperCamelCase
? "StringList" : "stringlist";
60 sType
= bUpperCamelCase
? "FilterList" : "filterlist";
63 sType
= bUpperCamelCase
? "ItemList" : "itemlist";
66 sType
= bUpperCamelCase
? "PairedList" : "pairedlist";
77 FILE * init(int argc
, char ** argv
)
79 common::HandledArgs aArgs
;
80 if ( !common::handleArguments(argc
, argv
, aArgs
) )
82 common::writeUsage("transex3","*.src/*.hrc");
83 std::exit(EXIT_FAILURE
);
85 global::inputPathname
= aArgs
.m_sInputFile
;
87 FILE * pFile
= std::fopen(global::inputPathname
.getStr(), "r");
90 stderr
, "Error: Cannot open file \"%s\"\n",
91 global::inputPathname
.getStr());
92 std::exit(EXIT_FAILURE
);
95 if (aArgs
.m_bMergeMode
) {
96 global::exporter
.reset(new Export(aArgs
.m_sMergeSrc
, aArgs
.m_sOutputFile
,
97 aArgs
.m_sLanguage
, aArgs
.m_bUTF8BOM
));
99 global::exporter
.reset(new Export(aArgs
.m_sOutputFile
));
102 global::exporter
->Init();
107 int Parse( int nTyp
, const char *pTokenText
){
108 global::exporter
->Execute( nTyp
, pTokenText
);
114 global::exporter
->GetParseQueue()->Close();
115 global::exporter
.reset();
116 // avoid nontrivial Export dtor being executed during exit
119 int WorkOnTokenSet( int nTyp
, char *pTokenText
)
121 global::exporter
->GetParseQueue()->Push( QueueEntry( nTyp
, OString(pTokenText
) ) );
127 // set error at global instance of class Export
128 global::exporter
->SetError();
134 // get error at global instance of class Export
135 if (global::exporter
->GetError())
146 bool ResData::SetId( const OString
& rId
, sal_uInt16 nLevel
)
148 if ( nLevel
> nIdLevel
)
153 if ( bChild
&& bChildWithText
)
155 OString
sError("ResId after child definition");
156 yyerror(sError
.getStr());
160 if ( sId
.getLength() > 255 )
162 YYWarning( "LocalId > 255 chars, truncating..." );
163 sId
= sId
.copy(0, 255).trim();
179 static sal_Int32
lcl_countOccurrences(const OString
& text
, char c
)
182 for (sal_Int32 i
= 0;; ++i
) {
183 i
= text
.indexOf(c
, i
);
194 Export::Export(const OString
&rOutput
)
197 bNextMustBeDefineEOL( false ),
205 sFilename( global::inputPathname
),
206 sLanguages( OString() ),
207 pParseQueue( new ParserQueue( *this ) )
209 aOutput
.mPo
= new PoOfstream( rOutput
, PoOfstream::APP
);
210 if (!aOutput
.mPo
->isOpen())
212 std::fprintf(stderr
, "ERROR : Can't open file %s\n", rOutput
.getStr());
213 std::exit(EXIT_FAILURE
);
218 const OString
&rMergeSource
, const OString
&rOutput
,
219 const OString
&rLanguage
, bool bUTF8BOM
)
222 bNextMustBeDefineEOL( false ),
228 sMergeSrc( rMergeSource
),
231 sFilename( global::inputPathname
),
232 sLanguages( rLanguage
),
233 pParseQueue( new ParserQueue( *this ) )
235 aOutput
.mSimple
= new std::ofstream();
236 aOutput
.mSimple
->open(rOutput
.getStr(), std::ios_base::out
| std::ios_base::trunc
);
237 if (!aOutput
.mSimple
->is_open())
239 std::fprintf(stderr
, "ERROR : Can't open file %s\n", rOutput
.getStr());
240 std::exit(EXIT_FAILURE
);
243 if ( bUTF8BOM
) WriteUTF8ByteOrderMarkToOutput();
248 // resets the internal status, used before parseing another file
250 bNextMustBeDefineEOL
= false;
254 for ( size_t i
= 0, n
= aResStack
.size(); i
< n
; ++i
)
255 delete aResStack
[ i
];
265 aOutput
.mSimple
->close();
266 delete aOutput
.mSimple
;
270 aOutput
.mPo
->close();
273 for ( size_t i
= 0, n
= aResStack
.size(); i
< n
; ++i
)
274 delete aResStack
[ i
];
278 if ( !pMergeDataFile
)
279 pMergeDataFile
= new MergeDataFile(sMergeSrc
, global::inputPathname
, true);
281 delete pMergeDataFile
;
285 int Export::Execute( int nToken
, const char * pToken
)
288 OString
sToken( pToken
);
289 OString
sOrig( sToken
);
291 if ( nToken
== CONDITION
)
293 OString
sTestToken(pToken
);
294 sTestToken
= sTestToken
.replaceAll("\t", OString()).
295 replaceAll(" ", OString());
296 if (( !bReadOver
) && ( sTestToken
.startsWith("#ifndef__RSC_PARSER")))
298 else if (( bReadOver
) && ( sTestToken
.startsWith("#endif") ))
301 if ((( nToken
< FILTER_LEVEL
) || ( bReadOver
)) &&
302 (!(( bNextMustBeDefineEOL
) && ( sOrig
== "\n" )))) {
303 // this tokens are not mandatory for parsing, so ignore them ...
305 WriteToMerged( sOrig
, false ); // ... or write them directly to dest.
309 ResData
*pResData
= NULL
;
311 // res. exists at cur. level
312 pResData
= ( (nLevel
-1) < aResStack
.size() ) ? aResStack
[ nLevel
-1 ] : NULL
;
314 else if (( nToken
!= RESOURCE
) &&
315 ( nToken
!= RESOURCEEXPR
) &&
316 ( nToken
!= SMALRESOURCE
) &&
317 ( nToken
!= LEVELUP
) &&
318 ( nToken
!= NORMDEFINE
) &&
319 ( nToken
!= RSCDEFINE
) &&
320 ( nToken
!= CONDITION
) &&
321 ( nToken
!= PRAGMA
))
323 // no res. exists at cur. level so return
325 WriteToMerged( sOrig
, false );
330 if (( nToken
!= EMPTYLINE
) && ( nToken
!= LEVELDOWN
) && ( nToken
!= LEVELUP
)) {
331 // cur. res. defined in macro
332 if ( bNextMustBeDefineEOL
) {
333 if ( nToken
!= RSCDEFINELEND
) {
334 // end of macro found, so destroy res.
336 Execute( LEVELDOWN
, "" );
337 bNextMustBeDefineEOL
= false;
340 // next line also in macro definition
341 bNextMustBeDefineEOL
= false;
343 WriteToMerged( sOrig
, false );
350 bool bExecuteDown
= false;
351 if ( nToken
!= LEVELDOWN
) {
352 sal_uInt16 nOpen
= 0;
353 sal_uInt16 nClose
= 0;
354 bool bReadOver1
= false;
356 for ( i
= 0; i
< sToken
.getLength(); i
++ ) {
357 if ( sToken
[i
] == '"' )
358 bReadOver1
= !bReadOver1
;
359 if ( !bReadOver1
&& ( sToken
[i
] == '{' ))
364 for ( i
= 0; i
< sToken
.getLength(); i
++ ) {
365 if ( sToken
[i
] == '"' )
366 bReadOver1
= !bReadOver1
;
367 if ( !bReadOver1
&& ( sToken
[i
] == '}' ))
371 if ( nOpen
< nClose
)
375 bool bWriteToMerged
= bMergeMode
;
380 WriteToMerged( sOrig
, false );
383 bDefine
= true; // res. defined in macro
387 if ( nToken
!= RSCDEFINE
)
388 bNextMustBeDefineEOL
= false;
389 // this is the beginning of a new res.
392 aResStack
[ nLevel
- 2 ]->bChild
= true;
395 // create new instance for this res. and fill mandatory fields
397 pResData
= new ResData( FullId() , sFilename
);
398 aResStack
.push_back( pResData
);
399 sToken
= sToken
.replaceAll("\n", OString()).
400 replaceAll("\r", OString()).
401 replaceAll("{", OString()).replace('\t', ' ');
402 sToken
= sToken
.trim();
403 OString sTLower
= sToken
.getToken(0, ' ').toAsciiLowerCase();
404 pResData
->sResTyp
= sTLower
;
405 OString
sId( sToken
.copy( pResData
->sResTyp
.getLength() + 1 ));
407 if ( sId
.indexOf( '#' ) != -1 )
409 // between ResTyp, Id and paranthes is a precomp. condition
412 sId
= sId
.getToken(0, '#', n
);
413 sCondition
+= sId
.getToken(0, '#', n
);
415 sId
= sId
.getToken(0, '/');
417 sId
= sId
.replaceAll("\t", OString());
418 pResData
->SetId( sId
, ID_LEVEL_IDENTIFIER
);
419 if (!sCondition
.isEmpty())
421 Execute( CONDITION
, ""); // execute the precomp. condition
426 // this is the beginning of a new res.
427 bNextMustBeDefineEOL
= false;
430 aResStack
[ nLevel
- 2 ]->bChild
= true;
433 // create new instance for this res. and fill mandatory fields
435 pResData
= new ResData( FullId() , sFilename
);
436 aResStack
.push_back( pResData
);
437 sToken
= sToken
.replaceAll("\n", OString()).
438 replaceAll("\r", OString()).
439 replaceAll("{", OString()).
440 replaceAll("\t", OString()).
441 replaceAll(" ", OString()).
442 replaceAll("\\", OString()).toAsciiLowerCase();
443 pResData
->sResTyp
= sToken
;
456 sLowerTyp
= "unknown";
459 aResStack
[ nLevel
- 2 ]->bChild
= true;
462 ResData
*pNewData
= new ResData( FullId() , sFilename
);
463 pNewData
->sResTyp
= sLowerTyp
;
464 aResStack
.push_back( pNewData
);
469 if ( !nList
|| !nListLevel
) {
471 if ( bDefine
&& (nLevel
== 1 )) {
473 bNextMustBeDefineEOL
= false;
475 WriteData( pResData
);
476 ResStack::iterator it
= aResStack
.begin();
477 ::std::advance( it
, nLevel
-1 );
479 aResStack
.erase( it
);
491 bNextMustBeDefineEOL
= true;
498 // interpret different types of assignement
500 OString sKey
= sToken
.getToken(0, '=', n
).
501 replaceAll(" ", OString()).
502 replaceAll("\t", OString());
503 OString sValue
= sToken
.getToken(0, '=', n
);
504 CleanValue( sValue
);
505 sKey
= sKey
.toAsciiUpperCase();
506 if (sKey
== "IDENTIFIER")
509 sValue
.replaceAll("\t", OString()).
510 replaceAll(" ", OString()));
511 pResData
->SetId(sId
, ID_LEVEL_IDENTIFIER
);
513 else if (sKey
=="STRINGLIST")
519 else if (sKey
== "FILTERLIST")
525 if (sToken
.indexOf( '{' ) != -1
526 && (lcl_countOccurrences(sToken
, '{')
527 > lcl_countOccurrences(sToken
, '}')))
529 Parse( LEVELUP
, "" );
536 sToken
.replaceAll(" ", OString()).toAsciiLowerCase());
537 sal_Int32 nPos
= sTmpToken
.indexOf("[en-us]=");
540 sTmpToken
.copy(0 , nPos
).replaceAll(" ", OString()).
541 replaceAll("\t", OString()));
542 OString sValue
= sToken
.getToken(1, '=');
543 CleanValue( sValue
);
544 sKey
= sKey
.toAsciiUpperCase();
545 if (sKey
== "STRINGLIST")
549 else if (sKey
== "FILTERLIST")
553 else if (sKey
== "PAIREDLIST")
557 else if (sKey
== "ITEMLIST")
572 // this is an entry for a List
576 InsertListEntry( sOrig
);
584 CutComment( sToken
);
586 // this is a text line!!!
587 OString
t(sToken
.getToken(0, '='));
589 t
.getToken(0, '[').replaceAll(" ", OString()).
590 replaceAll("\t", OString()));
591 OString
sText( GetText( sToken
, nToken
));
593 if ( sToken
.getToken(0, '=').indexOf('[') != -1 )
595 sLang
= sToken
.getToken(0, '=').getToken(1, '[').
599 OString sLangIndex
= sLang
;
600 OString sOrigKey
= sKey
;
601 if ( !sText
.isEmpty() && !sLang
.isEmpty() )
603 sKey
= sKey
.toAsciiUpperCase();
604 if (sKey
== "TEXT" || sKey
== "MESSAGE" || sKey
== "CUSTOMUNITTEXT")
607 if ( sLangIndex
.equalsIgnoreAsciiCase("en-US") )
608 pResData
->SetId( sText
, ID_LEVEL_TEXT
);
610 pResData
->bText
= true;
611 pResData
->sTextTyp
= sOrigKey
;
614 pResData
->sText
[ sLangIndex
] = sText
;
617 else if ( sKey
== "QUICKHELPTEXT" ) {
619 pResData
->bQuickHelpText
= true;
622 pResData
->sQuickHelpText
[ sLangIndex
] = sText
;
625 else if ( sKey
== "TITLE" ) {
627 pResData
->bTitle
= true;
630 pResData
->sTitle
[ sLangIndex
] = sText
;
641 if ( nLevel
&& pResData
) {
642 WriteData( pResData
, true );
648 bNextMustBeDefineEOL
= false;
651 Parse( LEVELDOWN
, "" );
656 std::fprintf(stderr
, "ERROR: archaic PRAGMA %s\n", sToken
.getStr());
657 std::exit(EXIT_FAILURE
);
661 if ( bWriteToMerged
) {
662 // the current token must be written to dest. without merging
664 if( bDefine
&& sOrig
.getLength() > 2 ){
665 for( sal_uInt16 n
= 0 ; n
< sOrig
.getLength() ; n
++ ){
666 if( sOrig
[n
] == '\n' && sOrig
[n
-1] != '\\'){
667 sOrig
= sOrig
.replaceAt(n
++, 0, "\\");
671 WriteToMerged( sOrig
, false);
674 if ( bExecuteDown
) {
675 Parse( LEVELDOWN
, "" );
681 void Export::CutComment( OString
&rText
)
683 if (rText
.indexOf("//") != -1) {
684 OString
sWork(rText
.replaceAll("\\\"", "XX"));
686 for (sal_Int32 i
= 0; i
< sWork
.getLength() - 1; ++i
) {
687 if (sWork
[i
] == '"') {
689 } else if (sWork
[i
] == '/' && !bInner
&& sWork
[i
+ 1] == '/' ) {
690 rText
= rText
.copy(0, i
);
697 bool Export::WriteData( ResData
*pResData
, bool bCreateNew
)
700 MergeRest( pResData
);
704 // mandatory to export: en-US
706 if (( !pResData
->sText
[ SOURCE_LANGUAGE
].isEmpty())
708 ( !pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
].isEmpty())
710 ( !pResData
->sTitle
[ SOURCE_LANGUAGE
].isEmpty()))
713 OString sGID
= pResData
->sGId
;
716 sGID
= pResData
->sId
;
718 sLID
= pResData
->sId
;
720 OString sXText
= pResData
->sText
[ SOURCE_LANGUAGE
];
721 OString sXHText
= pResData
->sText
[ X_COMMENT
];
722 OString sXQHText
= pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
];
723 OString sXTitle
= pResData
->sTitle
[ SOURCE_LANGUAGE
];
725 if( !sXText
.isEmpty() )
727 ConvertExportContent(sXText
);
728 ConvertExportContent(sXHText
);
729 common::writePoEntry(
730 "Transex3", *aOutput
.mPo
, global::inputPathname
,
731 pResData
->sResTyp
, sGID
, sLID
, sXHText
, sXText
);
733 if( !sXQHText
.isEmpty() )
735 ConvertExportContent(sXQHText
);
736 common::writePoEntry(
737 "Transex3", *aOutput
.mPo
, global::inputPathname
, pResData
->sResTyp
,
738 sGID
, sLID
, OString(), sXQHText
, PoEntry::TQUICKHELPTEXT
);
740 if( !sXTitle
.isEmpty() )
742 ConvertExportContent(sXTitle
);
743 common::writePoEntry(
744 "Transex3", *aOutput
.mPo
, global::inputPathname
, pResData
->sResTyp
,
745 sGID
, sLID
, OString(), sXTitle
, PoEntry::TTITLE
);
749 pResData
->sText
[ SOURCE_LANGUAGE
] = "";
750 pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
]= "";
751 pResData
->sTitle
[ SOURCE_LANGUAGE
] = "";
757 WriteExportList( pResData
, pResData
->m_aList
, nList
);
759 pResData
->m_aList
.clear();
764 OString
Export::GetPairedListID(const OString
& rText
)
766 // < "STRING" ; IDENTIFIER ; > ;
767 return rText
.getToken(1, ';').toAsciiUpperCase().replace('\t', ' ').trim();
770 OString
Export::GetPairedListString(const OString
& rText
)
772 // < "STRING" ; IDENTIFIER ; > ;
773 OString
sString(rText
.getToken(0, ';').replace('\t', ' '));
774 sString
= sString
.trim();
775 OString
s1(sString
.copy(sString
.indexOf('"') + 1));
776 sString
= s1
.copy(0, s1
.lastIndexOf('"'));
777 return sString
.trim();
780 OString
Export::StripList(const OString
& rText
)
782 OString s1
= rText
.copy( rText
.indexOf('\"') + 1);
783 return s1
.copy( 0 , s1
.lastIndexOf('\"'));
786 bool Export::WriteExportList(ResData
*pResData
, ExportList
& rExportList
,
787 const sal_uInt16 nTyp
)
789 OString
sGID(pResData
->sGId
);
791 sGID
= pResData
->sId
;
794 sGID
+= pResData
->sId
;
795 while (sGID
.endsWith(".")) {
796 sGID
= sGID
.copy(0, sGID
.getLength() - 1);
800 for ( size_t i
= 0; i
< rExportList
.size(); i
++ )
803 OString
sText(rExportList
[ i
]);
805 // Strip PairList Line String
806 if (nTyp
== LIST_PAIRED
)
808 sLID
= GetPairedListID( sText
);
809 sText
= GetPairedListString( sText
);
813 sText
= StripList( sText
);
814 if( sText
== "\\\"" )
817 ConvertExportContent(sText
);
819 if (nTyp
!= LIST_PAIRED
)
822 OString sType
= lcl_GetListTyp( nList
, false );
824 common::writePoEntry(
825 "Transex3", *aOutput
.mPo
, global::inputPathname
,
826 sType
, sGID
, sLID
, OString(), sText
);
832 OString
Export::FullId()
837 sFull
.append(aResStack
[ 0 ]->sId
);
838 for ( size_t i
= 1; i
< nLevel
- 1; ++i
)
840 OString sToAdd
= aResStack
[ i
]->sId
;
841 if (!sToAdd
.isEmpty())
842 sFull
.append('.').append(sToAdd
);
845 if (sFull
.getLength() > 255)
847 OString
sError("GroupId > 255 chars");
848 printf("GroupID = %s\n", sFull
.getStr());
849 yyerror(sError
.getStr());
852 return sFull
.makeStringAndClear();
855 void Export::InsertListEntry(const OString
&rLine
)
857 ResData
*pResData
= ( nLevel
-1 < aResStack
.size() ) ? aResStack
[ nLevel
-1 ] : NULL
;
860 std::exit(EXIT_FAILURE
);
862 if( pResData
->m_aList
.empty() )
865 pResData
->m_aList
.push_back(rLine
);
868 void Export::CleanValue( OString
&rValue
)
870 while ( !rValue
.isEmpty()) {
871 if (( rValue
[0] == ' ' ) || ( rValue
[0] == '\t' ))
872 rValue
= rValue
.copy( 1 );
877 if ( !rValue
.isEmpty()) {
878 for ( sal_Int32 i
= rValue
.getLength() - 1; i
> 0; i
-- ) {
879 if (( rValue
[i
] == ' ' ) || ( rValue
[i
] == '\t' ) ||
880 ( rValue
[i
] == '\n' ) || ( rValue
[i
] == ';' ) ||
881 ( rValue
[i
] == '{' ) || ( rValue
[i
] == '\\' ) ||
882 ( rValue
[i
] == '\r' ))
883 rValue
= rValue
.copy(0, i
);
890 #define TXT_STATE_TEXT 0x001
891 #define TXT_STATE_MACRO 0x002
893 OString
Export::GetText(const OString
&rSource
, int nToken
)
901 OString
sTmp(rSource
.copy(rSource
.indexOf('=')));
903 sTmp
= sTmp
.replaceAll("\n", OString()).
904 replaceAll("\r", OString()).
905 replaceAll("\\\\\"", "-=<[BSlashBSlashHKom]>=-\"").
906 replaceAll("\\\"", "-=<[Hochkomma]>=-").
907 replaceAll("\\\x7f", "-=<[0x7F]>=-").
908 replaceAll("\\0x7F", "-=<[0x7F]>=-");
910 sal_uInt16 nState
= TXT_STATE_TEXT
;
911 for (sal_Int32 i
= 1; i
<= lcl_countOccurrences(sTmp
, '"'); ++i
)
913 OString
sToken(sTmp
.getToken(i
, '"'));
914 if (!sToken
.isEmpty()) {
915 if ( nState
== TXT_STATE_TEXT
) {
917 nState
= TXT_STATE_MACRO
;
920 sToken
= sToken
.replace('\t', ' ');
923 sToken
= sToken
.replaceFirst(" ", " ", &n
);
928 sToken
= sToken
.trim();
929 if (!sToken
.isEmpty()) {
934 nState
= TXT_STATE_TEXT
;
939 sReturn
= sReturn
.replaceAll("-=<[0x7F]>=-", "\x7f").
940 replaceAll("-=<[Hochkomma]>=-", "\"").
941 replaceAll("-=<[BSlashBSlashHKom]>=-", "\\\\").
942 replaceAll("\\\\", "-=<[BSlashBSlash]>=-").
943 replaceAll("-=<[BSlashBSlash]>=-", "\\");
950 void Export::WriteToMerged(const OString
&rText
, bool bSDFContent
)
952 OString
sText(rText
);
955 sText
= sText
.replaceFirst(" \n", "\n", &n
);
960 if (pParseQueue
->bNextIsM
&& bSDFContent
&& sText
.getLength() > 2) {
961 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
962 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
963 sText
= sText
.replaceAt(n
++, 0, "\\");
966 } else if (pParseQueue
->bLastWasM
&& sText
.getLength() > 2) {
967 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
968 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
969 sText
= sText
.replaceAt(n
++, 0, "\\");
971 if (sText
[n
] == '\n') {
972 pParseQueue
->bMflag
= true;
975 } else if (pParseQueue
->bCurrentIsM
&& bSDFContent
&& sText
.getLength() > 2)
977 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
978 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
979 sText
= sText
.replaceAt(n
++, 0, "\\");
980 pParseQueue
->bMflag
= true;
983 } else if (pParseQueue
->bMflag
) {
984 for (sal_Int32 n
= 1; n
< sText
.getLength(); ++n
) {
985 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
986 sText
= sText
.replaceAt(n
++, 0, "\\");
989 } for (sal_Int32 i
= 0; i
< sText
.getLength(); ++i
) {
990 if (sText
[i
] == '\n') {
991 *aOutput
.mSimple
<< '\n';
993 char cChar
= sText
[i
];
994 *aOutput
.mSimple
<< cChar
;
999 void Export::ConvertMergeContent( OString
&rText
)
1001 rText
= rText
.replaceAll("\\\'","\'"); // Temporary: until PO files contain escaped single quotes
1002 // (Maybe next PO update solve this)
1005 rText
.replaceAll("\x7f","\\0x7F"),
1006 "\n""\t""\\""\"","\\n""\\t""\\\\""\\\"");
1008 rText
= "\"" + rText
+ "\"";
1011 void Export::ConvertExportContent( OString
& rText
)
1013 rText
= helper::unEscapeAll(rText
,"\\n""\\t""\\\\""\\\"","\n""\t""\\""\"");
1016 void Export::ResData2Output( MergeEntrys
*pEntry
, sal_uInt16 nType
, const OString
& rTextType
)
1018 bool bAddSemicolon
= false;
1022 for( unsigned int n
= 0; n
< aLanguages
.size(); n
++ ){
1023 sCur
= aLanguages
[ n
];
1026 bool bText
= pEntry
->GetText( sText
, nType
, sCur
, true );
1027 if ( bText
&& !sText
.isEmpty() ) {
1028 OStringBuffer sOutput
;
1029 if ( bNextMustBeDefineEOL
) {
1031 sOutput
.append("\t\\\n");
1033 sOutput
.append(";\t\\\n");
1036 sOutput
.append("\t" + rTextType
);
1038 if ( !sCur
.equalsIgnoreAsciiCase("en-US") ) {
1039 sOutput
.append("[ " + sCur
+ " ] ");
1042 ConvertMergeContent( sText
);
1043 sOutput
.append("= " + sText
);
1046 sOutput
.append(";\\\n");
1047 else if ( !bNextMustBeDefineEOL
)
1048 sOutput
.append(";\n");
1050 bAddSemicolon
= true;
1051 for ( sal_uInt16 j
= 1; j
< nLevel
; j
++ )
1052 sOutput
.append("\t");
1053 WriteToMerged( sOutput
.makeStringAndClear() , true );
1058 if ( bAddSemicolon
) {
1059 WriteToMerged( ";" , false );
1063 void Export::MergeRest( ResData
*pResData
)
1065 if ( !pMergeDataFile
){
1066 pMergeDataFile
= new MergeDataFile( sMergeSrc
, global::inputPathname
, true );
1067 aLanguages
= pMergeDataFile
->GetLanguages();
1071 MergeEntrys
*pEntry
= 0;
1072 if( pResData
->bText
|| pResData
->bQuickHelpText
|| pResData
->bTitle
)
1073 pEntry
= pMergeDataFile
->GetMergeEntrysCaseSensitive( pResData
);
1077 if ( pResData
->bText
)
1078 ResData2Output( pEntry
, STRING_TYP_TEXT
, pResData
->sTextTyp
);
1080 if ( pResData
->bQuickHelpText
)
1081 ResData2Output( pEntry
, STRING_TYP_QUICKHELPTEXT
, OString("QuickHelpText") );
1083 if ( pResData
->bTitle
)
1084 ResData2Output( pEntry
, STRING_TYP_TITLE
, OString("Title") );
1090 OString sOldId
= pResData
->sId
;
1091 OString sOldGId
= pResData
->sGId
;
1092 OString sOldTyp
= pResData
->sResTyp
;
1094 // Set pResData so we can find the corresponding string
1095 if (!pResData
->sGId
.isEmpty())
1096 pResData
->sGId
= pResData
->sGId
+ OString('.');
1097 pResData
->sGId
= pResData
->sGId
+ pResData
->sId
;
1099 pResData
->sResTyp
= lcl_GetListTyp( nList
, false );
1102 for ( sal_uInt16 i
= 1; i
< nLevel
-1; i
++ )
1106 for( unsigned int n
= 0; n
< aLanguages
.size(); n
++ )
1108 sCur
= aLanguages
[ n
];
1110 sal_uInt16 nLIndex
= 0;
1111 sal_uInt16 nMaxIndex
= pResData
->m_aList
.size();
1112 while( nLIndex
< nMaxIndex
)
1116 OStringBuffer sHead
;
1117 if ( bNextMustBeDefineEOL
)
1118 sHead
.append("\\\n\t");
1119 sHead
.append(sSpace
+ lcl_GetListTyp( nList
, true ) + " [ " + sCur
+ " ] ");
1121 if ( bDefine
|| bNextMustBeDefineEOL
)
1123 sHead
.append("= \\\n" + sSpace
+ "\t{\\\n\t");
1127 sHead
.append("= \n" + sSpace
+ "\t{\n\t");
1129 WriteToMerged(sHead
.makeStringAndClear() , true);
1132 OString sLine
= pResData
->m_aList
[ nLIndex
];
1133 if ( sLine
.indexOf( '>' ) != -1 )
1135 if ((( sLine
.indexOf( '{' ) == -1 ) ||
1136 ( sLine
.indexOf( '{' ) >= sLine
.indexOf( '"' ))) &&
1137 (( sLine
.indexOf( '<' ) == -1 ) ||
1138 ( sLine
.indexOf( '<' ) >= sLine
.indexOf( '"' ))))
1140 sLine
= sLine
.replaceFirst("\"", "< \"" );
1144 // Set matching identifier
1145 if ( nList
== LIST_PAIRED
)
1147 pResData
->sId
= GetPairedListID ( sLine
);
1153 sLine
.indexOf('"')+1,
1154 sLine
.lastIndexOf('"')-sLine
.indexOf('"')-1);
1155 ConvertExportContent( pResData
->sId
);
1158 MergeEntrys
* pEntrys
= pMergeDataFile
->GetMergeEntrysCaseSensitive( pResData
);
1163 pEntrys
->GetText( sText
, STRING_TYP_TEXT
, sCur
, false );
1164 if( !sText
.isEmpty())
1166 ConvertMergeContent( sText
);
1168 sLine
.copy( 0 , sLine
.indexOf('"') ) +
1170 sLine
.copy( sLine
.lastIndexOf('"') + 1 );
1174 OString
sText1( "\t" );
1176 if ( bDefine
|| bNextMustBeDefineEOL
)
1182 WriteToMerged( sText1
,true );
1189 if (!sSpace
.isEmpty())
1190 sFooter
= sSpace
.copy(1);
1192 if ( bNextMustBeDefineEOL
)
1194 else if ( !bDefine
)
1195 sFooter
+= "};\n\t";
1198 WriteToMerged( sFooter
,true );
1201 pResData
->sId
= sOldId
;
1202 pResData
->sGId
= sOldGId
;
1203 pResData
->sResTyp
= sOldTyp
;
1205 pParseQueue
->bMflag
= false;
1208 void Export::SetChildWithText()
1210 if ( aResStack
.size() > 1 ) {
1211 for ( size_t i
= 0; i
< aResStack
.size() - 1; i
++ ) {
1212 aResStack
[ i
]->bChildWithText
= true;
1217 void ParserQueue::Push( const QueueEntry
& aEntry
)
1219 sal_Int32 nLen
= aEntry
.sLine
.getLength();
1222 aQueueCur
->push( aEntry
);
1223 if( nLen
> 1 && aEntry
.sLine
[nLen
-1] == '\n' )
1225 else if ( aEntry
.nTyp
!= IGNOREDTOKENS
){
1226 if( nLen
> 1 && ( aEntry
.sLine
[nLen
-1] == '\\') ){
1231 bCurrentIsM
= false;
1236 aQueueNext
->push( aEntry
);
1237 if( nLen
> 1 && aEntry
.sLine
[nLen
-1] != '\n' ){
1238 if( nLen
> 1 && ( aEntry
.sLine
[nLen
-1] == '\\') ){
1246 }else if( nLen
> 2 && aEntry
.sLine
[nLen
-1] == '\n' ){
1247 if( aEntry
.nTyp
!= IGNOREDTOKENS
){
1248 if( nLen
> 2 && ( aEntry
.sLine
[nLen
-2] == '\\') ){
1259 bLastWasM
= bCurrentIsM
;
1261 bCurrentIsM
= bNextIsM
;
1262 std::queue
<QueueEntry
>* aQref
= aQueueCur
;
1263 aQueueCur
= aQueueNext
;
1271 bLastWasM
= bCurrentIsM
;
1273 bCurrentIsM
= bNextIsM
;
1274 std::queue
<QueueEntry
>* aQref
= aQueueCur
;
1275 aQueueCur
= aQueueNext
;
1281 void ParserQueue::Close(){
1285 bLastWasM
= bCurrentIsM
;
1286 bCurrentIsM
= bNextIsM
;
1287 std::queue
<QueueEntry
>* aQref
= aQueueCur
;
1288 aQueueCur
= aQueueNext
;
1294 void ParserQueue::Pop( std::queue
<QueueEntry
>& aQueue
)
1296 while (!aQueue
.empty())
1298 QueueEntry aEntry
= aQueue
.front();
1300 aExport
.Execute(aEntry
.nTyp
, aEntry
.sLine
.getStr());
1304 ParserQueue::ParserQueue( Export
& aExportObj
)
1306 bCurrentIsM( false ),
1310 aExport( aExportObj
) ,
1313 aQueueNext
= new std::queue
<QueueEntry
>;
1314 aQueueCur
= new std::queue
<QueueEntry
>;
1318 ParserQueue::~ParserQueue(){
1319 if( aQueueNext
) delete aQueueNext
;
1320 if( aQueueCur
) delete aQueueCur
;
1323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */