office-gobmx/l10ntools/source/cfgmerge.cxx
Andras Timar 3f00358bfd export x-comments to sdf file into the 'helptext' field
helptext field has not been in use for a while, so we can
use that to hold the x-comment
2012-04-14 14:24:06 +02:00

672 lines
21 KiB
C++

/* -*- 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
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#include "common.hxx"
#include "sal/config.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#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: */