Kaydet (Commit) 0fd7f81e authored tarafından Zolnai Tamás's avatar Zolnai Tamás

Implement new treex executable

Which localize and update help tree files
instead of update_tree.pl.
Use it to update extensions' help.
Next step: use it with general help.

Change-Id: Ife9696bdd8b973ef3cf30626533e38720408179b
üst ef941c6e
......@@ -69,6 +69,7 @@ $(eval $(call gb_Helper_register_executables,NONE, \
svg2odf \
svidl \
transex3 \
treex \
typesconfig \
$(if $(filter UCPP,$(BUILD_TYPE)),\
ucpp \
......
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# 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/.
#
$(eval $(call gb_Executable_Executable,treex))
$(eval $(call gb_Executable_set_include,treex,\
-I$(SRCDIR)/l10ntools/inc \
$$(INCLUDE) \
))
$(eval $(call gb_Executable_use_libraries,treex,\
sal \
i18nregexp \
))
$(eval $(call gb_Executable_use_static_libraries,treex,\
transex \
))
$(eval $(call gb_Executable_add_exception_objects,treex,\
l10ntools/source/treemerge \
l10ntools/source/treex \
))
$(eval $(call gb_Executable_use_externals,treex,\
libxml2 \
))
# vim: set noet sw=4 ts=4:
......@@ -39,6 +39,7 @@ $(eval $(call gb_Module_add_targets,l10ntools,\
Executable_transex3 \
Executable_renewpo \
Executable_propex \
Executable_treex \
StaticLibrary_transex \
Package_inc \
Package_scripts \
......
/* -*- 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/.
*/
#ifndef _TREEMERGE_INCLUDED
#define _TREEMERGE_INCLUDED
#include <libxml/tree.h>
#include <rtl/string.hxx>
#include <vector>
class TreeParser
{
private:
xmlDocPtr m_pSource;
OString m_sLang;
bool m_bIsInitialized;
public:
TreeParser(
const OString& rInputFile, const OString& rLang );
~TreeParser();
bool isInitialized() const { return m_bIsInitialized; }
void Extract(
const OString& rSDFFile, const OString& rPrj, const OString& rRoot );
void Merge(
const OString &rMergeSrc, const OString &rDestinationFile,
const OString &rXhpRoot );
};
#endif //_TREEMERGE_INCLUDED
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -324,7 +324,8 @@ void handleFile(
{ RTL_CONSTASCII_STRINGPARAM(".xml"), "xrmex", true },
{ RTL_CONSTASCII_STRINGPARAM(".xhp"), "helpex", false },
{ RTL_CONSTASCII_STRINGPARAM(".properties"), "propex", false },
{ RTL_CONSTASCII_STRINGPARAM(".ui"), "uiex", false } };
{ RTL_CONSTASCII_STRINGPARAM(".ui"), "uiex", false },
{ RTL_CONSTASCII_STRINGPARAM(".tree"), "treex", false } };
for (std::size_t i = 0; i != SAL_N_ELEMENTS(commands); ++i) {
if (url.endsWithAsciiL(
commands[i].extension, commands[i].extensionLength))
......
/* -*- 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/.
*/
#include <iostream>
#include <fstream>
#include <cassert>
#include <cstring>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
#include <libxml/xmlstring.h>
#include "export.hxx"
#include "common.hxx"
#include "treemerge.hxx"
namespace
{
//Write out an sdf line
static void lcl_WriteSDF(
std::ofstream &aSDFStream, const OString& rText, const OString& rPrj,
const OString& rActFileName, const OString& rID, const OString& rType )
{
OString sOutput( rPrj ); sOutput += "\t";
sOutput += rActFileName;
sOutput += "\t0\t";
sOutput += rType; sOutput += "\t";
sOutput += rID; sOutput += "\t\t\t\t0\ten-US\t";
sOutput += rText; sOutput += "\t\t\t\t";
aSDFStream << sOutput.getStr() << std::endl;
}
//Convert xmlChar* to OString
static OString lcl_xmlStrToOString( const xmlChar* pString )
{
xmlChar* pTemp = xmlStrdup( pString );
OString sResult =
static_cast<OString>(reinterpret_cast<sal_Char*>( pTemp ));
xmlFree( pTemp );
return sResult;
}
//Extract strings from nodes on all level recursively
static void lcl_ExtractLevel(
const xmlDocPtr pSource, const xmlNodePtr pRoot,
const xmlChar* pNodeName, std::ofstream& rSDFStream,
const OString& rPrj, const OString& rRoot )
{
if( !pRoot->children )
{
return;
}
for( xmlNodePtr pCurrent = pRoot->children->next;
pCurrent; pCurrent = pCurrent->next)
{
if (!xmlStrcmp(pCurrent->name, pNodeName))
{
xmlChar* pID = xmlGetProp(pCurrent, (const xmlChar*)("id"));
xmlChar* pText =
xmlGetProp(pCurrent, (const xmlChar*)("title"));
lcl_WriteSDF(
rSDFStream,
lcl_xmlStrToOString( pText ),
rPrj,
common::pathnameToken(
pSource->name, rRoot.getStr()),
lcl_xmlStrToOString( pID ),
lcl_xmlStrToOString( pNodeName ));
xmlFree( pID );
xmlFree( pText );
lcl_ExtractLevel(
pSource, pCurrent, (const xmlChar *)("node"),
rSDFStream, rPrj, rRoot );
}
}
}
//Update id and content of the topic
static xmlNodePtr lcl_UpdateTopic(
const xmlNodePtr pCurrent, const OString& rXhpRoot )
{
xmlNodePtr pReturn = pCurrent;
xmlChar* pID = xmlGetProp(pReturn, (const xmlChar*)("id"));
const OString sID =
lcl_xmlStrToOString( pID );
xmlFree( pID );
const sal_Int32 nFirstSlash = sID.indexOf("/");
//Update id attribute of topic
{
OString sNewID =
sID.copy( 0, nFirstSlash + 1 ) +
rXhpRoot.copy( rXhpRoot.lastIndexOf("/") + 1 ) +
sID.copy( sID.indexOf( "/", nFirstSlash + 1 ) );
xmlSetProp(
pReturn, (const xmlChar*)("id"),
reinterpret_cast<const xmlChar*>(sNewID.getStr()));
}
const OString sXhpPath =
rXhpRoot +
sID.copy(sID.indexOf("/", nFirstSlash + 1));
xmlDocPtr pXhpFile = xmlParseFile( sXhpPath.getStr() );
//if xhpfile is missing than we put this topic into comment
if ( !pXhpFile )
{
xmlNodePtr pTemp = pReturn;
xmlChar* sNewID =
xmlGetProp(pReturn, (const xmlChar*)("id"));
xmlChar* sComment =
xmlStrcat( xmlCharStrdup("removed "), sNewID );
pReturn = xmlNewComment( sComment );
xmlReplaceNode( pTemp, pReturn );
xmlFree( pTemp );
xmlFree( sNewID );
xmlFree( sComment );
}
//update topic's content on the basis of xhpfile's title
else
{
xmlNodePtr pXhpNode = xmlDocGetRootElement( pXhpFile );
for( pXhpNode = pXhpNode->children;
pXhpNode; pXhpNode = pXhpNode->children )
{
while( pXhpNode->type != XML_ELEMENT_NODE )
{
pXhpNode = pXhpNode->next;
}
if(!xmlStrcmp(pXhpNode->name, (const xmlChar *)("title")))
{
xmlChar* sTitle =
xmlNodeListGetString(pXhpFile, pXhpNode->children, 1);
OString sNewTitle =
lcl_xmlStrToOString( sTitle ).
replaceAll("$[officename]","%PRODUCTNAME").
replaceAll("$[officeversion]","%PRODUCTVERSION");
xmlNodeSetContent(
pReturn,
reinterpret_cast<const xmlChar*>( sNewTitle.getStr() ));
xmlFree( sTitle );
break;
}
}
if( !pXhpNode )
{
std::cerr
<< "Treex error: Cannot find title in "
<< sXhpPath.getStr() << std::endl;
return 0;
}
xmlFree( pXhpFile );
xmlCleanupParser();
}
return pReturn;
}
//Localize title attribute of help_section and node tags
static void lcl_MergeLevel(
xmlDocPtr io_pSource, const xmlNodePtr pRoot,
const xmlChar * pNodeName, MergeDataFile* pMergeDataFile,
const OString& rLang, const OString& rXhpRoot )
{
if( !pRoot->children )
{
return;
}
for( xmlNodePtr pCurrent = pRoot->children;
pCurrent; pCurrent = pCurrent->next)
{
if( !xmlStrcmp(pCurrent->name, pNodeName) )
{
if( pMergeDataFile )
{
xmlChar* pID = xmlGetProp(pCurrent, (const xmlChar*)("id"));
ResData aResData(
"", lcl_xmlStrToOString( pID ),
static_cast<OString>(io_pSource->name) );
xmlFree( pID );
aResData.sResTyp = lcl_xmlStrToOString( pNodeName );
PFormEntrys* pEntrys =
pMergeDataFile->GetPFormEntrys( &aResData );
if( pEntrys )
{
OString sNewText;
pEntrys->GetText( sNewText, STRING_TYP_TEXT, rLang );
xmlSetProp(
pCurrent, (const xmlChar*)("title"),
(const xmlChar*)(sNewText.getStr()));
}
}
lcl_MergeLevel(
io_pSource, pCurrent, (const xmlChar *)("node"),
pMergeDataFile, rLang, rXhpRoot );
}
else if( !xmlStrcmp(pCurrent->name, (const xmlChar *)("topic")) )
{
pCurrent = lcl_UpdateTopic( pCurrent, rXhpRoot );
}
}
}
}
//Parse tree file
TreeParser::TreeParser(
const OString& rInputFile, const OString& rLang )
: m_pSource( 0 )
, m_sLang( rLang )
, m_bIsInitialized( false )
{
m_pSource = xmlParseFile( rInputFile.getStr() );
if ( !m_pSource ) {
std::cerr
<< "Treex error: Cannot open source file: "
<< rInputFile.getStr() << std::endl;
return;
}
if( !m_pSource->name )
{
m_pSource->name = new char[strlen(rInputFile.getStr())+1];
strcpy( m_pSource->name, rInputFile.getStr() );
}
m_bIsInitialized = true;
}
TreeParser::~TreeParser()
{
}
//Extract strings form source file
void TreeParser::Extract(
const OString& rSDFFile, const OString& rPrj, const OString& rRoot )
{
assert( m_bIsInitialized );
std::ofstream aSDFStream(
rSDFFile.getStr(), std::ios_base::out | std::ios_base::trunc );
if( !aSDFStream.is_open() )
{
std::cerr
<< "Treex error: Cannot open sdffile for extract: "
<< rSDFFile.getStr() << std::endl;
return;
}
xmlNodePtr pRootNode = xmlDocGetRootElement( m_pSource );
lcl_ExtractLevel(
m_pSource, pRootNode, (const xmlChar *)("help_section"),
aSDFStream, rPrj, rRoot );
xmlFreeDoc( m_pSource );
xmlCleanupParser();
aSDFStream.close();
m_bIsInitialized = false;
}
//Merge strings to tree file and update reference to help files(xhp)
void TreeParser::Merge(
const OString &rMergeSrc, const OString &rDestinationFile,
const OString &rXhpRoot )
{
assert( m_bIsInitialized );
const xmlNodePtr pRootNode = xmlDocGetRootElement( m_pSource );
if( m_sLang == "en-US" )
{
lcl_MergeLevel(
m_pSource, pRootNode, (const xmlChar *)("help_section"),
0, m_sLang, rXhpRoot );
}
else
{
MergeDataFile aMergeDataFile(
rMergeSrc, static_cast<OString>( m_pSource->name ), false );
if( aMergeDataFile.GetLanguages()[0] != m_sLang )
{
std::cerr
<< "Treex error: given language conflicts with "
<< "language of Mergedata file: "
<< m_sLang.getStr() << " - " << rMergeSrc.getStr() << std::endl;
return;
}
lcl_MergeLevel(
m_pSource, pRootNode, (const xmlChar *)("help_section"),
&aMergeDataFile, m_sLang, rXhpRoot );
}
xmlSaveFile( rDestinationFile.getStr(), m_pSource );
xmlFreeDoc( m_pSource );
xmlCleanupParser();
m_bIsInitialized = false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- 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/.
*/
#include <iostream>
#include "sal/main.h"
#include "export.hxx"
#include "treemerge.hxx"
void WriteUsage()
{
std::cout
<< "Syntax: Treex [-p Prj] [-r Root] -i FileIn -o FileOut"
<< " [-m DataBase] [-l l1,l2,...]\n"
<< " Prj: Project\n"
<< " Root: Path to project root (../.. etc.)\n"
<< " or path to root of localized xhp files\n"
<< " FileIn: Source files (*.tree)\n"
<< " FileOut: Destination file (*.*)\n"
<< " DataBase: Mergedata (*.po)\n"
<< " -l: Restrict the handled languages; l1, l2, ... are elements of"
<< " (de, en-US, ...)\n";
}
SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
HandledArgs aArgs;
if( !Export::handleArguments(argc, argv, aArgs) )
{
WriteUsage();
return 1;
}
TreeParser aParser(aArgs.m_sInputFile, Export::sLanguages);
if( !aParser.isInitialized() )
{
return 1;
}
if( aArgs.m_bMergeMode || aArgs.m_sPrj.isEmpty() )
{
aParser.Merge(
aArgs.m_sMergeSrc, aArgs.m_sOutputFile, aArgs.m_sPrjRoot );
}
else
{
aParser.Extract(
aArgs.m_sOutputFile, aArgs.m_sPrj, aArgs.m_sPrjRoot );
}
return 0;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -39,11 +39,9 @@ gb_ExtensionTarget_PROPMERGETARGET := $(call gb_Executable_get_target_for_build,
gb_ExtensionTarget_PROPMERGECOMMAND := \
$(gb_Helper_set_ld_path) $(gb_ExtensionTarget_PROPMERGETARGET)
gb_ExtensionTarget_UPDATETREETARGET := $(SRCDIR)/l10ntools/scripts/update_tree.pl
gb_ExtensionTarget_UPDATETREECOMMAND := \
$(gb_Helper_set_ld_path) $(PERL) $(gb_ExtensionTarget_UPDATETREETARGET)
# update_tree.pl calls xmllint, which needs $(gb_Helper_set_ld_path) if it
# is the internal one
gb_ExtensionTarget_TREEXTARGET := $(call gb_Executable_get_target_for_build,treex)
gb_ExtensionTarget_TREEXCOMMAND := \
$(gb_Helper_set_ld_path) $(gb_ExtensionTarget_TREEXTARGET)
gb_ExtensionTarget_HELPEXTARGET := $(call gb_Executable_get_target_for_build,helpex)
gb_ExtensionTarget_HELPEXCOMMAND := \
......@@ -261,9 +259,8 @@ endef
# suffix
# $(3): relative path of (target) help.tree file (e.g.,
# com.sun.wiki-publisher/help.tree)
# $(4): optional relative path of source help.tree file, when it differs from $(3)
# (i.e., if $(4) is empty the en-US source file is $(2)/$(3), otherwise it
# is $(2)/$(4))
# $(4): relative path of source help.tree file
# $(5): relative path of localized xhp files (PlatformID included)
define gb_ExtensionTarget_add_helptreefile
$(foreach lang,$(gb_ExtensionTarget_ALL_LANGS), \
$(call gb_ExtensionTarget__localize_helptreefile_onelang,$(1),$(2),$(3),$(4),$(lang),$(5)) \
......@@ -322,38 +319,44 @@ $(call gb_ExtensionTarget_get_workdir,$(1))/help/$(5)/$(3) : \
endef
# localize one help.tree for one language; the result is stored as
# help/$(4)/$(3) in the extension's workdir; as a special case, if $(4) is
# "en-US", the source file is just copied, not passed through update_tree.pl
# help/$(4)/$(3) in the extension's workdir;
# $(1): extension identifier
# $(2): absolute path prefix of en-US source file without $(3) (resp. $(4))
# suffix
# $(3): relative path of (target) help.tree file (see
# gb_ExtensionTarget_add_helptreefile)
# $(4): optional relative path of source help.tree file (see
# $(4): relative path of source help.tree file (see
# gb_ExtensionTarget_add_helptreefile)
# $(5): language
# $(6): relative path of localized xhp files (PlatformID included)
define gb_ExtensionTarget__localize_helptreefile_onelang
$(call gb_ExtensionTarget_get_rootdir,$(1))/help/$(5).done : \
$(call gb_ExtensionTarget_get_rootdir,$(1))/help/$(5)/$(3)
ifneq ($(strip $(gb_WITH_LANG)),)
ifneq ($(filter-out en-US,$(5)),)
$(call gb_ExtensionTarget_get_rootdir,$(1))/help/$(5)/$(3) : \
POFILE := $(gb_POLOCATION)/$(5)$(subst $(SRCDIR),,$(2))$(patsubst %/,/%.po,$(patsubst ./,.po,$(dir $(or $(4),$(3)))))
POFILE := $(gb_POLOCATION)/$(5)$(subst $(SRCDIR),,$(2))$(patsubst %/,/%.po,$(patsubst ./,.po,$(dir $(4))))
$(call gb_ExtensionTarget_get_rootdir,$(1))/help/$(5)/$(3) : \
$(gb_POLOCATION)/$(5)$(subst $(SRCDIR),,$(2))$(patsubst %/,/%.po,$(patsubst ./,.po,$(dir $(or $(4),$(3)))))
$(gb_POLOCATION)/$(5)$(subst $(SRCDIR),,$(2))$(patsubst %/,/%.po,$(patsubst ./,.po,$(dir $(4))))
endif
endif
$(call gb_ExtensionTarget_get_rootdir,$(1))/help/$(5)/$(3) : \
$(if $(filter-out en-US,$(5)),$(gb_ExtensionTarget_UPDATETREETARGET)) | \
$(gb_ExtensionTarget_TREEXTARGET) | \
$(2)/$(4)
$(call gb_ExtensionTarget_get_rootdir,$(1))/help/$(5)/$(3) : \
$(2)/$(or $(4),$(3))
$$(call gb_Output_announce,$(1) $(3) $(5),$(true),TRE,3)
$$(call gb_Helper_abbreviate_dirs, \
mkdir -p $$(dir $$@) && \
mkdir -p $$(dir $$@) && \
$(if $(filter-out en-US,$(5)), \
cp $$< $$@,\
cp $$< $$@))
MERGEINPUT=`$(gb_MKTEMP)` && \
echo $$(POFILE) > $$$${MERGEINPUT} && \
$(gb_ExtensionTarget_TREEXCOMMAND) -i $$< -o $$@ -l $(5) \
-m $$$${MERGEINPUT} \
-r $$(call gb_ExtensionTarget_get_workdir,$(1))/help/$(5)/$(6) && \
rm -rf $$$${MERGEINPUT}, \
$(gb_ExtensionTarget_TREEXCOMMAND) -i $$< -o $$@ -l $(5) \
-r $$(call gb_ExtensionTarget_get_workdir,$(1))/help/$(5)/$(6) ))
endef
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment