3b24dcc8a8
A simplified version of the semantic match that finds this problem is follows: (http://coccinelle.lip6.fr/) // <smpl> @r1@ statement S; position p,p1; @@ S@p1;@p @script:python r2@ p << r1.p; p1 << r1.p1; @@ if p[0].line != p1[0].line_end: cocci.include_match(False) @@ position r1.p; @@ -;@p // </smpl> Change-Id: Ib9708d37fbb4c6060f88d5dae3814a2d37b2091e Reviewed-on: https://gerrit.libreoffice.org/9493 Reviewed-by: Noel Grandin <noelgrandin@gmail.com> Tested-by: Noel Grandin <noelgrandin@gmail.com>
318 lines
9.4 KiB
C++
318 lines
9.4 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include "sal/config.h"
|
|
|
|
#include <cstddef>
|
|
#include <fstream>
|
|
#include <iterator>
|
|
#include <string>
|
|
|
|
#include "po.hxx"
|
|
#include "lngmerge.hxx"
|
|
|
|
namespace {
|
|
|
|
OString getBracketedContent(const OString& text) {
|
|
return text.getToken(1, '[').getToken(0, ']');
|
|
}
|
|
|
|
static void lcl_RemoveUTF8ByteOrderMarker( OString &rString )
|
|
{
|
|
if( rString.getLength() >= 3 && rString[0] == '\xEF' &&
|
|
rString[1] == '\xBB' && rString[2] == '\xBF' )
|
|
{
|
|
rString = rString.copy(3);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// class LngParser
|
|
|
|
LngParser::LngParser(const OString &rLngFile)
|
|
: nError( LNG_OK )
|
|
, pLines( NULL )
|
|
, sSource( rLngFile )
|
|
{
|
|
pLines = new LngLineList();
|
|
std::ifstream aStream(sSource.getStr());
|
|
if (aStream.is_open())
|
|
{
|
|
bool bFirstLine = true;
|
|
std::string s;
|
|
std::getline(aStream, s);
|
|
while (!aStream.eof())
|
|
{
|
|
OString sLine(s.data(), s.length());
|
|
|
|
if( bFirstLine )
|
|
{
|
|
// Always remove UTF8 BOM from the first line
|
|
lcl_RemoveUTF8ByteOrderMarker( sLine );
|
|
bFirstLine = false;
|
|
}
|
|
|
|
pLines->push_back( new OString(sLine) );
|
|
std::getline(aStream, s);
|
|
}
|
|
pLines->push_back( new OString() );
|
|
}
|
|
else
|
|
nError = LNG_COULD_NOT_OPEN;
|
|
}
|
|
|
|
LngParser::~LngParser()
|
|
{
|
|
for ( size_t i = 0, n = pLines->size(); i < n; ++i )
|
|
delete (*pLines)[ i ];
|
|
pLines->clear();
|
|
delete pLines;
|
|
}
|
|
|
|
bool LngParser::CreatePO( const OString &rPOFile )
|
|
{
|
|
PoOfstream aPOStream( rPOFile, PoOfstream::APP );
|
|
if (!aPOStream.isOpen()) {
|
|
std::cerr << "Ulfex error: Can't open po file:" << rPOFile.getStr() << "\n";
|
|
}
|
|
|
|
size_t nPos = 0;
|
|
bool bStart = true;
|
|
OString sGroup, sLine;
|
|
OStringHashMap Text;
|
|
OString sID;
|
|
|
|
while( nPos < pLines->size() ) {
|
|
sLine = *(*pLines)[ nPos++ ];
|
|
while( nPos < pLines->size() && !isNextGroup( sGroup , sLine ) ) {
|
|
ReadLine( sLine , Text );
|
|
sID = sGroup;
|
|
sLine = *(*pLines)[ nPos++ ];
|
|
}
|
|
if( bStart ) {
|
|
bStart = false;
|
|
sID = sGroup;
|
|
}
|
|
else {
|
|
WritePO( aPOStream , Text , sSource , sID );
|
|
}
|
|
}
|
|
aPOStream.close();
|
|
return true;
|
|
}
|
|
|
|
void LngParser::WritePO(PoOfstream &aPOStream,
|
|
OStringHashMap &rText_inout, const OString &rActFileName,
|
|
const OString &rID)
|
|
{
|
|
|
|
bool bExport = true;
|
|
if ( bExport )
|
|
{
|
|
common::writePoEntry(
|
|
"Ulfex", aPOStream, rActFileName, "LngText",
|
|
rID, OString(), OString(), rText_inout["en-US"]);
|
|
}
|
|
}
|
|
|
|
bool LngParser::isNextGroup(OString &sGroup_out, const OString &sLine_in)
|
|
{
|
|
const OString sLineTrim = sLine_in.trim();
|
|
if (sLineTrim.startsWith("[") && sLineTrim.endsWith("]"))
|
|
{
|
|
sGroup_out = getBracketedContent(sLineTrim).trim();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LngParser::ReadLine(const OString &rLine_in,
|
|
OStringHashMap &rText_inout)
|
|
{
|
|
if (!rLine_in.match(" *") && !rLine_in.match("/*"))
|
|
{
|
|
OString sLang(rLine_in.getToken(0, '=').trim());
|
|
if (!sLang.isEmpty()) {
|
|
OString sText(rLine_in.getToken(1, '"'));
|
|
rText_inout[sLang] = sText;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool LngParser::Merge(
|
|
const OString &rPOFile,
|
|
const OString &rDestinationFile,
|
|
const OString &rLanguage )
|
|
{
|
|
std::ofstream aDestination(
|
|
rDestinationFile.getStr(), std::ios_base::out | std::ios_base::trunc);
|
|
if (!aDestination.is_open()) {
|
|
nError = LNG_COULD_NOT_OPEN;
|
|
}
|
|
nError = LNG_OK;
|
|
|
|
MergeDataFile aMergeDataFile( rPOFile, sSource, false, true );
|
|
if( rLanguage.equalsIgnoreAsciiCase("ALL") )
|
|
aLanguages = aMergeDataFile.GetLanguages();
|
|
|
|
size_t nPos = 0;
|
|
bool bGroup = false;
|
|
OString sGroup;
|
|
|
|
// seek to next group
|
|
while ( nPos < pLines->size() && !bGroup )
|
|
{
|
|
OString sLine( *(*pLines)[ nPos ] );
|
|
sLine = sLine.trim();
|
|
if ( sLine.startsWith("[") && sLine.endsWith("]") )
|
|
{
|
|
sGroup = getBracketedContent(sLine).trim();
|
|
bGroup = true;
|
|
}
|
|
nPos ++;
|
|
}
|
|
|
|
while ( nPos < pLines->size()) {
|
|
OStringHashMap Text;
|
|
OString sID( sGroup );
|
|
std::size_t nLastLangPos = 0;
|
|
|
|
ResData *pResData = new ResData( sID, sSource );
|
|
pResData->sResTyp = "LngText";
|
|
MergeEntrys *pEntrys = aMergeDataFile.GetMergeEntrys( pResData );
|
|
// read languages
|
|
bGroup = false;
|
|
|
|
OString sLanguagesDone;
|
|
|
|
while ( nPos < pLines->size() && !bGroup )
|
|
{
|
|
OString sLine( *(*pLines)[ nPos ] );
|
|
sLine = sLine.trim();
|
|
if ( sLine.startsWith("[") && sLine.endsWith("]") )
|
|
{
|
|
sGroup = getBracketedContent(sLine).trim();
|
|
bGroup = true;
|
|
nPos ++;
|
|
sLanguagesDone = "";
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 n = 0;
|
|
OString sLang(sLine.getToken(0, '=', n));
|
|
if (n == -1 || static_cast<bool>(sLine.match("/*")))
|
|
{
|
|
++nPos;
|
|
}
|
|
else
|
|
{
|
|
sLang = sLang.trim();
|
|
|
|
OString sSearch( ";" );
|
|
sSearch += sLang;
|
|
sSearch += ";";
|
|
|
|
if (( sLanguagesDone.indexOf( sSearch ) != -1 )) {
|
|
LngLineList::iterator it = pLines->begin();
|
|
std::advance( it, nPos );
|
|
pLines->erase( it );
|
|
}
|
|
if( pEntrys )
|
|
{
|
|
if( !sLang.isEmpty() )
|
|
{
|
|
OString sNewText;
|
|
pEntrys->GetText( sNewText, STRING_TYP_TEXT, sLang, true );
|
|
if( sLang == "qtz" )
|
|
continue;
|
|
|
|
if ( !sNewText.isEmpty()) {
|
|
OString *pLine = (*pLines)[ nPos ];
|
|
|
|
OString sText1( sLang );
|
|
sText1 += " = \"";
|
|
// escape quotes, unescape double escaped quotes fdo#56648
|
|
sText1 += sNewText.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
|
|
sText1 += "\"";
|
|
*pLine = sText1;
|
|
Text[ sLang ] = sNewText;
|
|
}
|
|
}
|
|
nLastLangPos = nPos;
|
|
nPos ++;
|
|
sLanguagesDone += sSearch;
|
|
}
|
|
else {
|
|
nLastLangPos = nPos;
|
|
nPos ++;
|
|
sLanguagesDone += sSearch;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
OString sCur;
|
|
if ( nLastLangPos )
|
|
{
|
|
for(size_t n = 0; n < aLanguages.size(); ++n)
|
|
{
|
|
sCur = aLanguages[ n ];
|
|
if( !sCur.equalsIgnoreAsciiCase("en-US") && Text[sCur].isEmpty() && pEntrys )
|
|
{
|
|
|
|
OString sNewText;
|
|
pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur, true );
|
|
if( sCur == "qtz" )
|
|
continue;
|
|
if ( !sNewText.isEmpty() && sCur != "x-comment")
|
|
{
|
|
OString sLine;
|
|
sLine += sCur;
|
|
sLine += " = \"";
|
|
// escape quotes, unescape double escaped quotes fdo#56648
|
|
sLine += sNewText.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
|
|
sLine += "\"";
|
|
|
|
nLastLangPos++;
|
|
nPos++;
|
|
|
|
if ( nLastLangPos < pLines->size() ) {
|
|
LngLineList::iterator it = pLines->begin();
|
|
std::advance( it, nLastLangPos );
|
|
pLines->insert( it, new OString(sLine) );
|
|
} else {
|
|
pLines->push_back( new OString(sLine) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete pResData;
|
|
}
|
|
|
|
for ( size_t i = 0; i < pLines->size(); ++i )
|
|
aDestination << (*pLines)[i]->getStr() << '\n';
|
|
|
|
aDestination.close();
|
|
return true;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|