/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org 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. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ #include "common.hxx" #include "sal/config.h" #include #include #include #include "boost/scoped_ptr.hpp" #include "rtl/strbuf.hxx" #include "common.hxx" #include "export.hxx" #include "cfgmerge.hxx" #include "tokens.h" extern "C" { int yyerror(char const *); } namespace { namespace global { bool mergeMode = false; bool errorLog = true; char const * prj = 0; char const * prjRoot = 0; char const * inputPathname = 0; char const * outputPathname = 0; char const * mergeSrc; boost::scoped_ptr< CfgParser > parser; } void handleArguments(int argc, char ** argv) { for (int i = 1; i != argc; ++i) { if (std::strcmp(argv[i], "-e") == 0) { global::errorLog = false; } else if (std::strcmp(argv[i], "-i") == 0) { if (++i == argc) { global::inputPathname = 0; // no valid command line break; } global::inputPathname = argv[i]; } else if (std::strcmp(argv[i], "-l") == 0) { if (++i == argc) { global::inputPathname = 0; // no valid command line break; } Export::sLanguages = argv[i]; } else if (std::strcmp(argv[i], "-m") == 0) { if (++i == argc) { global::inputPathname = 0; // no valid command line break; } global::mergeSrc = argv[i]; global::mergeMode = true; } else if (std::strcmp(argv[i], "-o") == 0) { if (++i == argc) { global::inputPathname = 0; // no valid command line break; } global::outputPathname = argv[i]; } else if (std::strcmp(argv[i], "-p") == 0) { if (++i == argc) { global::inputPathname = 0; // no valid command line break; } global::prj = argv[i]; } else if (std::strcmp(argv[i], "-r") == 0) { if (++i == argc) { global::inputPathname = 0; // no valid command line break; } global::prjRoot = argv[i]; } else { global::inputPathname = 0; // no valid command line break; } } if (global::inputPathname == 0 || global::outputPathname == 0) { std::fprintf( stderr, ("Syntax: cfgex [-p Prj] [-r PrjRoot] -i FileIn -o FileOut" " [-m DataBase] [-e] [-l l1,l2,...]\n" " Prj: Project\n" " PrjRoot: Path to project root (../.. etc.)\n" " FileIn: Source files (*.src)\n" " FileOut: Destination file (*.*)\n" " DataBase: Mergedata (*.sdf)\n" " -e: Disable writing errorlog\n" " -l: Restrict the handled languages; l1, l2, ... are elements of" " (de, en-US, ...)\n")); std::exit(EXIT_FAILURE); } Export::InitLanguages(); } } extern "C" { FILE * init(int argc, char ** argv) { handleArguments(argc, argv); FILE * pFile = std::fopen(global::inputPathname, "r"); if (pFile == 0) { std::fprintf( stderr, "Error: Cannot open file \"%s\"\n", global::inputPathname); std::exit(EXIT_FAILURE); } if (global::mergeMode) { global::parser.reset( new CfgMerge( global::mergeSrc, global::outputPathname, global::inputPathname)); } else { global::parser.reset( new CfgExport( global::outputPathname, global::prj, common::pathnameToken(global::inputPathname, global::prjRoot))); } return pFile; } void workOnTokenSet(int nTyp, char * pTokenText) { global::parser->Execute( nTyp, pTokenText ); } } // // class CfgStackData // CfgStackData* CfgStack::Push(const rtl::OString &rTag, const rtl::OString &rId) { CfgStackData *pD = new CfgStackData( rTag, rId ); maList.push_back( pD ); return pD; } // // class CfgStack // /*****************************************************************************/ CfgStack::~CfgStack() /*****************************************************************************/ { for ( size_t i = 0, n = maList.size(); i < n; i++ ) delete maList[ i ]; maList.clear(); } rtl::OString CfgStack::GetAccessPath( size_t nPos ) { rtl::OStringBuffer sReturn; for (size_t i = 0; i <= nPos; ++i) { if (i) sReturn.append('.'); sReturn.append(maList[i]->GetIdentifier()); } return sReturn.makeStringAndClear(); } /*****************************************************************************/ CfgStackData *CfgStack::GetStackData() /*****************************************************************************/ { if (!maList.empty()) return maList[maList.size() - 1]; else return 0; } // // class CfgParser // /*****************************************************************************/ CfgParser::CfgParser() /*****************************************************************************/ : pStackData( NULL ), bLocalize( sal_False ) { } CfgParser::~CfgParser() { } sal_Bool CfgParser::IsTokenClosed(const rtl::OString &rToken) { return rToken[rToken.getLength() - 2] == '/'; } /*****************************************************************************/ void CfgParser::AddText( rtl::OString &rText, const rtl::OString &rIsoLang, const rtl::OString &rResTyp ) /*****************************************************************************/ { rText = rText.replaceAll(rtl::OString('\n'), rtl::OString()). replaceAll(rtl::OString('\r'), rtl::OString()). replaceAll(rtl::OString('\t'), rtl::OString()); pStackData->sResTyp = rResTyp; WorkOnText( rText, rIsoLang ); pStackData->sText[ rIsoLang ] = rText; } /*****************************************************************************/ int CfgParser::ExecuteAnalyzedToken( int nToken, char *pToken ) /*****************************************************************************/ { rtl::OString sToken( pToken ); if ( sToken == " " || sToken == "\t" ) sLastWhitespace += sToken; rtl::OString sTokenName; rtl::OString sTokenId; sal_Bool bOutput = sal_True; switch ( nToken ) { case CFG_TOKEN_PACKAGE: case CFG_TOKEN_COMPONENT: case CFG_TOKEN_TEMPLATE: case CFG_TOKEN_CONFIGNAME: case CFG_TOKEN_OORNAME: case CFG_TOKEN_OORVALUE: case CFG_TAG: case ANYTOKEN: case CFG_TEXT_START: { sTokenName = sToken.getToken(1, '<').getToken(0, '>'). getToken(0, ' '); if ( !IsTokenClosed( sToken )) { rtl::OString sSearch; switch ( nToken ) { case CFG_TOKEN_PACKAGE: sSearch = "package-id="; break; case CFG_TOKEN_COMPONENT: sSearch = "component-id="; break; case CFG_TOKEN_TEMPLATE: sSearch = "template-id="; break; case CFG_TOKEN_CONFIGNAME: sSearch = "cfg:name="; break; case CFG_TOKEN_OORNAME: sSearch = "oor:name="; bLocalize = sal_True; break; case CFG_TOKEN_OORVALUE: sSearch = "oor:value="; break; case CFG_TEXT_START: { if ( sCurrentResTyp != sTokenName ) { WorkOnRessourceEnd(); rtl::OString sCur; for( unsigned int i = 0; i < aLanguages.size(); ++i ){ sCur = aLanguages[ i ]; pStackData->sText[ sCur ] = rtl::OString(); } } sCurrentResTyp = sTokenName; rtl::OString sTemp = sToken.copy( sToken.indexOf( "xml:lang=" )); sCurrentIsoLang = sTemp.getToken(1, '"'); if ( sCurrentIsoLang == NO_TRANSLATE_ISO ) bLocalize = sal_False; pStackData->sTextTag = sToken; sCurrentText = ""; } break; } if ( !sSearch.isEmpty()) { rtl::OString sTemp = sToken.copy( sToken.indexOf( sSearch )); sTokenId = sTemp.getToken(1, '"'); } pStackData = aStack.Push( sTokenName, sTokenId ); if ( sSearch == "cfg:name=" ) { rtl::OString sTemp( sToken.toAsciiUpperCase() ); bLocalize = (( sTemp.indexOf( "CFG:TYPE=\"STRING\"" ) != -1 ) && ( sTemp.indexOf( "CFG:LOCALIZED=\"sal_True\"" ) != -1 )); } } else if ( sTokenName == "label" ) { if ( sCurrentResTyp != sTokenName ) { WorkOnRessourceEnd(); rtl::OString sCur; for( unsigned int i = 0; i < aLanguages.size(); ++i ){ sCur = aLanguages[ i ]; pStackData->sText[ sCur ] = rtl::OString(); } } sCurrentResTyp = sTokenName; } } break; case CFG_CLOSETAG: { sTokenName = sToken.getToken(1, '/').getToken(0, '>'). getToken(0, ' '); if ( aStack.GetStackData() && ( aStack.GetStackData()->GetTagType() == sTokenName )) { if (sCurrentText.isEmpty()) WorkOnRessourceEnd(); aStack.Pop(); pStackData = aStack.GetStackData(); } else { rtl::OString sError( "Misplaced close tag: " ); rtl::OString sInFile(" in file "); sError += sToken; sError += sInFile; sError += global::inputPathname; Error( sError ); std::exit(EXIT_FAILURE); } } break; case CFG_TEXTCHAR: sCurrentText += sToken; bOutput = sal_False; break; case CFG_TOKEN_NO_TRANSLATE: bLocalize = sal_False; break; } if ( !sCurrentText.isEmpty() && nToken != CFG_TEXTCHAR ) { AddText( sCurrentText, sCurrentIsoLang, sCurrentResTyp ); Output( sCurrentText ); sCurrentText = rtl::OString(); pStackData->sEndTextTag = sToken; } if ( bOutput ) Output( sToken ); if ( sToken != " " && sToken != "\t" ) sLastWhitespace = ""; return 1; } void CfgExport::Output(const rtl::OString&) { } /*****************************************************************************/ int CfgParser::Execute( int nToken, char * pToken ) /*****************************************************************************/ { rtl::OString sToken( pToken ); switch ( nToken ) { case CFG_TAG: if ( sToken.indexOf( "package-id=" ) != -1 ) return ExecuteAnalyzedToken( CFG_TOKEN_PACKAGE, pToken ); else if ( sToken.indexOf( "component-id=" ) != -1 ) return ExecuteAnalyzedToken( CFG_TOKEN_COMPONENT, pToken ); else if ( sToken.indexOf( "template-id=" ) != -1 ) return ExecuteAnalyzedToken( CFG_TOKEN_TEMPLATE, pToken ); else if ( sToken.indexOf( "cfg:name=" ) != -1 ) return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME, pToken ); else if ( sToken.indexOf( "oor:name=" ) != -1 ) return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME, pToken ); else if ( sToken.indexOf( "oor:value=" ) != -1 ) return ExecuteAnalyzedToken( CFG_TOKEN_OORVALUE, pToken ); break; } return ExecuteAnalyzedToken( nToken, pToken ); } void CfgParser::Error(const rtl::OString& rError) { yyerror(rError.getStr()); } // // class CfgOutputParser // CfgOutputParser::CfgOutputParser(const rtl::OString &rOutputFile) { pOutputStream.open( rOutputFile.getStr(), std::ios_base::out | std::ios_base::trunc); if (!pOutputStream.is_open()) { rtl::OStringBuffer sError(RTL_CONSTASCII_STRINGPARAM("ERROR: Unable to open output file: ")); sError.append(rOutputFile); Error(sError.makeStringAndClear()); std::exit(EXIT_FAILURE); } } /*****************************************************************************/ CfgOutputParser::~CfgOutputParser() /*****************************************************************************/ { pOutputStream.close(); } // // class CfgExport // /*****************************************************************************/ CfgExport::CfgExport( const rtl::OString &rOutputFile, const rtl::OString &rProject, const rtl::OString &rFilePath ) /*****************************************************************************/ : CfgOutputParser( rOutputFile ), sPrj( rProject ), sPath( rFilePath ) { Export::InitLanguages( false ); aLanguages = Export::GetLanguages(); } /*****************************************************************************/ CfgExport::~CfgExport() /*****************************************************************************/ { } /*****************************************************************************/ void CfgExport::WorkOnRessourceEnd() /*****************************************************************************/ { if ( bLocalize ) { if ( pStackData->sText[rtl::OString(RTL_CONSTASCII_STRINGPARAM("en-US"))].getLength() ) { rtl::OString sFallback = pStackData->sText[rtl::OString(RTL_CONSTASCII_STRINGPARAM("en-US"))]; rtl::OString sXComment = pStackData->sText[rtl::OString(RTL_CONSTASCII_STRINGPARAM("x-comment"))]; rtl::OString sLocalId = pStackData->sIdentifier; rtl::OString sGroupId; if ( aStack.size() == 1 ) { sGroupId = sLocalId; sLocalId = ""; } else { sGroupId = aStack.GetAccessPath( aStack.size() - 2 ); } for (size_t n = 0; n < aLanguages.size(); n++) { rtl::OString sCur = aLanguages[ n ]; rtl::OString sText = pStackData->sText[ sCur ]; if ( sText.isEmpty()) sText = sFallback; sText = Export::UnquoteHTML( sText ); rtl::OString sOutput( sPrj ); sOutput += "\t"; sOutput += sPath; sOutput += "\t0\t"; sOutput += pStackData->sResTyp; sOutput += "\t"; sOutput += sGroupId; sOutput += "\t"; sOutput += sLocalId; sOutput += "\t\t\t0\t"; sOutput += sCur; sOutput += "\t"; sOutput += sText; sOutput += "\t"; sOutput += sXComment; sOutput += "\t\t\t"; pOutputStream << sOutput.getStr() << '\n'; } } } } void CfgExport::WorkOnText( rtl::OString &rText, const rtl::OString &rIsoLang ) { if( rIsoLang.getLength() ) rText = Export::UnquoteHTML( rText ); } // // class CfgMerge // CfgMerge::CfgMerge( const rtl::OString &rMergeSource, const rtl::OString &rOutputFile, const rtl::OString &rFilename) : CfgOutputParser( rOutputFile ), pMergeDataFile( NULL ), pResData( NULL ), sFilename( rFilename ), bEnglish( sal_False ) { if (rMergeSource.getLength()) { pMergeDataFile = new MergeDataFile( rMergeSource, global::inputPathname, global::errorLog, true ); if (Export::sLanguages.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ALL"))) { Export::SetLanguages( pMergeDataFile->GetLanguages() ); aLanguages = pMergeDataFile->GetLanguages(); } else aLanguages = Export::GetLanguages(); } else aLanguages = Export::GetLanguages(); } /*****************************************************************************/ CfgMerge::~CfgMerge() /*****************************************************************************/ { delete pMergeDataFile; delete pResData; } void CfgMerge::WorkOnText(rtl::OString &rText, const rtl::OString& rLangIndex) { if ( pMergeDataFile && bLocalize ) { if ( !pResData ) { rtl::OString sLocalId = pStackData->sIdentifier; rtl::OString sGroupId; if ( aStack.size() == 1 ) { sGroupId = sLocalId; sLocalId = rtl::OString(); } else { sGroupId = aStack.GetAccessPath( aStack.size() - 2 ); } rtl::OString sPlatform; pResData = new ResData( sPlatform, sGroupId , sFilename ); pResData->sId = sLocalId; pResData->sResTyp = pStackData->sResTyp; } if (rLangIndex.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US"))) bEnglish = sal_True; PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrysCaseSensitive( pResData ); if ( pEntrys ) { rtl::OString sContent; pEntrys->GetText( sContent, STRING_TYP_TEXT, rLangIndex ); if ( Export::isAllowed( rLangIndex ) && ( sContent != "-" ) && !sContent.isEmpty()) { rText = Export::QuoteHTML( rText ); } } } } void CfgMerge::Output(const rtl::OString& rOutput) { pOutputStream << rOutput.getStr(); } /*****************************************************************************/ void CfgMerge::WorkOnRessourceEnd() /*****************************************************************************/ { if ( pMergeDataFile && pResData && bLocalize && bEnglish ) { PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrysCaseSensitive( pResData ); if ( pEntrys ) { rtl::OString sCur; for( unsigned int i = 0; i < aLanguages.size(); ++i ){ sCur = aLanguages[ i ]; rtl::OString sContent; pEntrys->GetText( sContent, STRING_TYP_TEXT, sCur , sal_True ); if ( ( !sCur.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")) ) && ( sContent != "-" ) && !sContent.isEmpty()) { rtl::OString sText = Export::QuoteHTML( sContent); rtl::OString sAdditionalLine( "\t" ); rtl::OString sTextTag = pStackData->sTextTag; rtl::OString sTemp = sTextTag.copy( sTextTag.indexOf( "xml:lang=" )); sal_Int32 n = 0; rtl::OString sSearch = sTemp.getToken(0, '"', n); sSearch += "\""; sSearch += sTemp.getToken(0, '"', n); sSearch += "\""; rtl::OString sReplace = sTemp.getToken(0, '"'); sReplace += "\""; sReplace += sCur; sReplace += "\""; sTextTag = sTextTag.replaceFirst(sSearch, sReplace); sAdditionalLine += sTextTag; sAdditionalLine += sText; sAdditionalLine += pStackData->sEndTextTag; sAdditionalLine += "\n"; sAdditionalLine += sLastWhitespace; Output( sAdditionalLine ); } } } } delete pResData; pResData = NULL; bEnglish = sal_False; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */