LibreOffice Module l10ntools (master) 1
xrmmerge.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <stdio.h>
23
24#include <common.hxx>
25#include <export.hxx>
26#include <po.hxx>
27#include <utility>
28#include <xrmlex.hxx>
29#include <xrmmerge.hxx>
30#include <tokens.h>
31#include <helper.hxx>
32#include <iostream>
33#include <vector>
34#include <memory>
35
36// set of global variables
37static bool bMergeMode;
38static bool bDisplayName;
40static OString sLanguage;
41static OString sInputFileName;
42static OString sOutputFile;
43static OString sMergeSrc;
44static OString sLangAttribute;
45static OString sResourceType;
46static XRMResParser *pParser = nullptr;
47
48extern "C" {
49// the whole interface to lexer is in this extern "C" section
50
51extern bool GetOutputFile( int argc, char* argv[])
52{
53 bDisplayName = false;
55
57 if ( common::handleArguments(argc, argv, aArgs) )
58 {
60 sLanguage = aArgs.m_sLanguage;
63 sMergeSrc = aArgs.m_sMergeSrc;
64 return true;
65 }
66 else
67 {
68 // command line is not valid
69 common::writeUsage("xrmex","*.xrm/*.xml");
70 return false;
71 }
72}
73
74int InitXrmExport( const char* pFilename)
75{
76 // instantiate Export
77 OString sFilename( pFilename );
78
79 if ( bMergeMode )
80 pParser = new XRMResMerge( sMergeSrc, sOutputFile, sFilename );
81 else if (!sOutputFile.isEmpty())
83
84 return 1;
85}
86
88{
89 delete pParser;
90 return 1;
91}
92extern const char* getFilename()
93{
94 return sInputFileName.getStr();
95}
96
98{
99 // look for valid filename
100 if (!sInputFileName.isEmpty()) {
101 //TODO: explicit BOM handling?
102 FILE * pFile = fopen(sInputFileName.getStr(), "r");
103 if ( !pFile ){
104 fprintf( stderr, "Error: Could not open file %s\n",
105 sInputFileName.getStr());
106 }
107 else {
108 return pFile;
109 }
110 }
111 // this means the file could not be opened
112 return nullptr;
113}
114
115int WorkOnTokenSet( int nTyp, char *pTokenText )
116{
117 //printf("Typ = %d , text = '%s'\n",nTyp , pTokenText );
118 pParser->Execute( nTyp, pTokenText );
119
120 return 1;
121}
122
124{
125 pParser->SetError();
126 return 1;
127}
128}
129
130extern "C" {
131
133{
134 return pParser->GetError();
135}
136}
137
138
139
140
142 : bError( false ),
143 bText( false )
144{
145}
146
148{
149}
150
151void XRMResParser::Execute( int nToken, char * pToken )
152{
153 OString rToken( pToken );
154
155 switch ( nToken ) {
156 case XRM_TEXT_START:{
157 OString sNewGID = GetAttribute( rToken, "id" );
158 if ( sNewGID != sGID ) {
159 sGID = sNewGID;
160 }
161 bText = true;
162 sCurrentText = OString();
163 sCurrentOpenTag = rToken;
164 Output( rToken );
165 }
166 break;
167
168 case XRM_TEXT_END: {
169 sCurrentCloseTag = rToken;
170 sResourceType = OString ( "readmeitem" );
171 sLangAttribute = OString ( "xml:lang" );
175 bText = false;
176 rToken = OString();
177 sCurrentText = OString();
178 }
179 break;
180
182 bDisplayName = true;
183 }
184 break;
185
187 bDisplayName = false;
188 }
189 break;
190
191 case DESC_TEXT_START:{
192 if (bDisplayName) {
193 sGID = OString("dispname");
194 bText = true;
195 sCurrentText = OString();
196 sCurrentOpenTag = rToken;
197 Output( rToken );
198 }
199 }
200 break;
201
202 case DESC_TEXT_END: {
203 if (bDisplayName) {
204 sCurrentCloseTag = rToken;
205 sResourceType = OString ( "description" );
206 sLangAttribute = OString ( "lang" );
210 bText = false;
211 rToken = OString();
212 sCurrentText = OString();
213 }
214 }
215 break;
216
219 }
220 break;
221
223 bExtensionDescription = false;
224 }
225 break;
226
229 sGID = OString("extdesc");
230 sResourceType = OString ( "description" );
231 sLangAttribute = OString ( "lang" );
232 sCurrentOpenTag = rToken;
233 sCurrentText = OString();
234 Output( rToken );
236 sCurrentCloseTag = rToken;
238 rToken = OString();
239 sCurrentText = OString();
240 }
241 }
242 break;
243
244 default:
245 if ( bText ) {
246 sCurrentText += rToken;
247 }
248 break;
249 }
250
251 if ( !bText )
252 {
253 Output( rToken );
254 }
255}
256
257OString XRMResParser::GetAttribute( const OString &rToken, std::string_view rAttribute )
258{
259 const OString sSearch{ OString::Concat(" ") + rAttribute + "=" };
260 OString sTmp{ rToken.replace('\t', ' ') };
261 sal_Int32 nPos = sTmp.indexOf( sSearch );
262
263 if ( nPos<0 )
264 return OString();
265
266 return sTmp.getToken(1, '"', nPos);
267}
268
269
270void XRMResParser::Error( const OString &rError )
271{
272 yyerror(rError.getStr());
273}
274
275
276
277
279 const OString &rOutputFile, OString _sFilePath )
280 : sPath(std::move( _sFilePath ))
281{
282 pOutputStream.open( rOutputFile, PoOfstream::APP );
283 if (!pOutputStream.isOpen())
284 {
285 Error( "Unable to open output file: " + rOutputFile );
286 }
287}
288
290{
292}
293
294void XRMResExport::Output( const OString& ) {}
295
297 const OString &rOpenTag,
298 OString &rText )
299{
300 const OString sDescFileName{ sInputFileName.replaceAll("description.xml", OString())
301 + GetAttribute( rOpenTag, "xlink:href" ) };
302 std::ifstream file (sDescFileName.getStr(), std::ios::in|std::ios::binary|std::ios::ate);
303 if (file.is_open()) {
304 int size = static_cast<int>(file.tellg());
305 std::unique_ptr<char[]> memblock(new char [size+1]);
306 file.seekg (0, std::ios::beg);
307 file.read (memblock.get(), size);
308 file.close();
309 memblock[size] = '\0';
310 rText = OString(memblock.get());
311 }
312 WorkOnText( rOpenTag, rText );
313 EndOfText( rOpenTag, rOpenTag );
314}
315
317 const OString &rOpenTag,
318 OString &rText )
319{
320 OString sLang( GetAttribute( rOpenTag, sLangAttribute ));
321
322 if ( !pResData )
323 {
324 pResData.reset( new ResData( GetGID() ) );
325 }
326 pResData->sText[sLang] = rText;
327}
328
330 const OString &,
331 const OString & )
332{
333 if ( pResData )
334 {
335 OString sAct = pResData->sText["en-US"];
336
337 if( !sAct.isEmpty() )
340 pResData->sGId, OString(), OString(), sAct );
341 }
342 pResData.reset();
343}
344
345
346
347
349 const OString &rMergeSource, const OString &rOutputFile,
350 OString _sFilename )
351 : sFilename(std::move( _sFilename ))
352{
353 if (!rMergeSource.isEmpty() && sLanguage.equalsIgnoreAsciiCase("ALL"))
354 {
356 rMergeSource, sInputFileName, false));
357 aLanguages = pMergeDataFile->GetLanguages();
358 }
359 else
360 aLanguages.push_back( sLanguage );
361 pOutputStream.open(
362 rOutputFile.getStr(), std::ios_base::out | std::ios_base::trunc);
363 if (!pOutputStream.is_open()) {
364 Error( "Unable to open output file: " + rOutputFile );
365 }
366}
367
369{
370 pOutputStream.close();
371}
372
374 const OString &rOpenTag,
375 OString &rText )
376{
377 WorkOnText( rOpenTag, rText);
378 if ( pMergeDataFile && pResData ) {
379 MergeEntrys *pEntrys = pMergeDataFile->GetMergeEntrys( pResData.get() );
380 if ( pEntrys ) {
381 OString sCur;
382 OString sDescFilename = GetAttribute ( rOpenTag, "xlink:href" );
383 for( size_t n = 0; n < aLanguages.size(); n++ ){
384 sCur = aLanguages[ n ];
385 OString sText;
386 if ( !sCur.equalsIgnoreAsciiCase("en-US") &&
387 ( pEntrys->GetText( sText, sCur, true )) &&
388 !sText.isEmpty())
389 {
390 OString sAdditionalLine{ "\n " + rOpenTag };
391 OString sSearch{ sLangAttribute + "=\"" };
392 OString sReplace( sSearch );
393
394 sSearch += GetAttribute( rOpenTag, sLangAttribute );
395 sReplace += sCur;
396 sAdditionalLine = sAdditionalLine.replaceFirst(
397 sSearch, sReplace);
398
399 sSearch = OString("xlink:href=\"");
400 sReplace = sSearch;
401
402 const OString sLocDescFilename = sDescFilename.replaceFirst( "en-US", sCur);
403
404 sSearch += sDescFilename;
405 sReplace += sLocDescFilename;
406 sAdditionalLine = sAdditionalLine.replaceFirst(
407 sSearch, sReplace);
408
409 Output( sAdditionalLine );
410
411 sal_Int32 i = sOutputFile.lastIndexOf('/');
412 if (i == -1) {
413 std::cerr
414 << "Error: output file " << sOutputFile
415 << " does not contain any /\n";
416 throw false; //TODO
417 }
418 OString sOutputDescFile(
419 sOutputFile.subView(0, i + 1) + sLocDescFilename);
420 std::ofstream file(sOutputDescFile.getStr());
421 if (file.is_open()) {
422 file << sText;
423 file.close();
424 } else {
425 std::cerr
426 << "Error: cannot write "
427 << sOutputDescFile << '\n';
428 throw false; //TODO
429 }
430 }
431 }
432 }
433 }
434 pResData.reset();
435}
436
438 const OString &,
439 OString & )
440{
441 if ( pMergeDataFile && !pResData ) {
442 pResData.reset( new ResData( GetGID(), sFilename ) );
443 pResData->sResTyp = sResourceType;
444 }
445}
446
447void XRMResMerge::Output( const OString& rOutput )
448{
449 if (!rOutput.isEmpty())
450 pOutputStream << rOutput;
451}
452
454 const OString &rOpenTag,
455 const OString &rCloseTag )
456{
457
458 Output( rCloseTag );
459 if ( pMergeDataFile && pResData ) {
460 MergeEntrys *pEntrys = pMergeDataFile->GetMergeEntrys( pResData.get() );
461 if ( pEntrys ) {
462 OString sCur;
463 for( size_t n = 0; n < aLanguages.size(); n++ ){
464 sCur = aLanguages[ n ];
465 OString sContent;
466 if (!sCur.equalsIgnoreAsciiCase("en-US") &&
467 ( pEntrys->GetText( sContent, sCur, true )) &&
468 !sContent.isEmpty() &&
469 helper::isWellFormedXML( sContent ))
470 {
471 const OString& sText( sContent );
472 OString sAdditionalLine{ "\n " + rOpenTag };
473 OString sSearch{ sLangAttribute + "=\"" };
474 OString sReplace( sSearch );
475
476 sSearch += GetAttribute( rOpenTag, sLangAttribute );
477 sReplace += sCur;
478
479 sAdditionalLine = sAdditionalLine.replaceFirst(
480 sSearch, sReplace) + sText + rCloseTag;
481
482 Output( sAdditionalLine );
483 }
484 }
485 }
486 }
487 pResData.reset();
488}
489
490/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static int bText
Definition: cfglex.l:54
void yyerror(const char *s)
Definition: cfglex.l:150
Purpose: holds information of data to merge, read from PO file.
Definition: export.hxx:114
Purpose: holds information of data to merge.
Definition: export.hxx:77
bool GetText(OString &rReturn, const OString &nLangIndex, bool bDel=false)
Definition: merge.cxx:87
void open(const OString &rFileName, OpenMode aMode=TRUNC)
Definition: po.cxx:498
bool isOpen() const
Definition: po.hxx:116
void close()
Definition: po.cxx:515
@ APP
Definition: po.hxx:109
Purpose: holds mandatory data to export a single res.
Definition: export.hxx:55
Export strings from *.xrm and description.xml files.
Definition: xrmmerge.hxx:79
XRMResExport(const OString &rOutputFile, OString sFilePath)
Definition: xrmmerge.cxx:278
void WorkOnDesc(const OString &rOpenTag, OString &rText) override
Definition: xrmmerge.cxx:296
void EndOfText(const OString &rOpenTag, const OString &rCloseTag) override
Definition: xrmmerge.cxx:329
OString sPath
Definition: xrmmerge.hxx:82
void Output(const OString &rOutput) override
Definition: xrmmerge.cxx:294
std::unique_ptr< ResData > pResData
Definition: xrmmerge.hxx:81
void WorkOnText(const OString &rOpenTag, OString &rText) override
Definition: xrmmerge.cxx:316
PoOfstream pOutputStream
Definition: xrmmerge.hxx:83
virtual ~XRMResExport() override
Definition: xrmmerge.cxx:289
Merge strings to *.xrm and description.xml files.
Definition: xrmmerge.hxx:110
void Output(const OString &rOutput) override
Definition: xrmmerge.cxx:447
std::vector< OString > aLanguages
Definition: xrmmerge.hxx:116
void WorkOnDesc(const OString &rOpenTag, OString &rText) override
Definition: xrmmerge.cxx:373
std::unique_ptr< MergeDataFile > pMergeDataFile
Definition: xrmmerge.hxx:112
std::ofstream pOutputStream
Definition: xrmmerge.hxx:115
void WorkOnText(const OString &rOpenTag, OString &rText) override
Definition: xrmmerge.cxx:437
void EndOfText(const OString &rOpenTag, const OString &rCloseTag) override
Definition: xrmmerge.cxx:453
virtual ~XRMResMerge() override
Definition: xrmmerge.cxx:368
OString sFilename
Definition: xrmmerge.hxx:113
XRMResMerge(const OString &rMergeSource, const OString &rOutputFile, OString sFilename)
Definition: xrmmerge.cxx:348
std::unique_ptr< ResData > pResData
Definition: xrmmerge.hxx:114
Parser for *.xrm and description.xml files.
Definition: xrmmerge.hxx:36
void SetError()
Definition: xrmmerge.hxx:72
bool GetError() const
Definition: xrmmerge.hxx:73
virtual void EndOfText(const OString &rOpenTag, const OString &rCloseTag)=0
virtual void WorkOnDesc(const OString &rOpenTag, OString &rText)=0
OString sGID
Definition: xrmmerge.hxx:38
OString sCurrentCloseTag
Definition: xrmmerge.hxx:44
static void Error(const OString &rError)
Definition: xrmmerge.cxx:270
const OString & GetGID() const
Definition: xrmmerge.hxx:64
static OString GetAttribute(const OString &rToken, std::string_view rAttribute)
Definition: xrmmerge.cxx:257
OString sCurrentText
Definition: xrmmerge.hxx:45
virtual void WorkOnText(const OString &rOpenTag, OString &rText)=0
virtual ~XRMResParser()
Definition: xrmmerge.cxx:147
virtual void Output(const OString &rOutput)=0
void Execute(int nToken, char *pToken)
Definition: xrmmerge.cxx:151
OString sCurrentOpenTag
Definition: xrmmerge.hxx:43
sal_Int64 n
sal_uInt16 nPos
size
void writeUsage(const OString &rName, const OString &rFileType)
Write out a help about usage.
Definition: common.cxx:97
void writePoEntry(const OString &rExecutable, PoOfstream &rPoStream, const OString &rSourceFile, std::string_view rResType, const OString &rGroupId, const OString &rLocalId, const OString &rHelpText, const OString &rText, const PoEntry::TYPE eType)
Write out a PoEntry with attention to exceptions.
Definition: common.cxx:110
bool handleArguments(int argc, char *argv[], HandledArgs &o_aHandledArgs)
Handle command line parameters.
Definition: common.cxx:25
int i
bool isWellFormedXML(std::string_view text)
Check whether text is a valid XML expression.
Definition: helper.cxx:130
DefTokenId nToken
Result type of handleArguments()
Definition: common.hxx:26
OString m_sMergeSrc
Definition: common.hxx:29
OString m_sOutputFile
Definition: common.hxx:28
OString m_sLanguage
Definition: common.hxx:30
OString m_sInputFile
Definition: common.hxx:27
#define XRM_TEXT_START
Definition: tokens.h:81
#define DESC_DISPLAY_NAME_END
Definition: tokens.h:91
#define DESC_TEXT_START
Definition: tokens.h:92
#define XRM_TEXT_END
Definition: tokens.h:82
#define DESC_EXTENSION_DESCRIPTION_END
Definition: tokens.h:95
#define DESC_EXTENSION_DESCRIPTION_SRC
Definition: tokens.h:96
#define DESC_EXTENSION_DESCRIPTION_START
Definition: tokens.h:94
#define DESC_DISPLAY_NAME_START
Definition: tokens.h:90
#define DESC_TEXT_END
Definition: tokens.h:93
int SetError()
Definition: xrmmerge.cxx:123
static OString sInputFileName
Definition: xrmmerge.cxx:41
static OString sLangAttribute
Definition: xrmmerge.cxx:44
int EndXrmExport()
Definition: xrmmerge.cxx:87
int GetError()
Definition: xrmmerge.cxx:132
int InitXrmExport(const char *pFilename)
Definition: xrmmerge.cxx:74
static OString sResourceType
Definition: xrmmerge.cxx:45
int WorkOnTokenSet(int nTyp, char *pTokenText)
Definition: xrmmerge.cxx:115
static OString sOutputFile
Definition: xrmmerge.cxx:42
static XRMResParser * pParser
Definition: xrmmerge.cxx:46
static bool bExtensionDescription
Definition: xrmmerge.cxx:39
static OString sLanguage
Definition: xrmmerge.cxx:40
static bool bMergeMode
Definition: xrmmerge.cxx:37
static OString sMergeSrc
Definition: xrmmerge.cxx:43
const char * getFilename()
Definition: xrmmerge.cxx:92
bool GetOutputFile(int argc, char *argv[])
Definition: xrmmerge.cxx:51
FILE * GetXrmFile()
Definition: xrmmerge.cxx:97
static bool bDisplayName
Definition: xrmmerge.cxx:38